# --- SET PARAMETERS FOR R MARKDOWN AND THE GENERAL RUNNING OF THE CODE --- #
set.seed(420)
knitr::opts_chunk$set(message = FALSE,
cache = FALSE,
autodep = FALSE)
start_time = Sys.time()
recompute_lengthy_analyses = FALSE
# --- SET PARAMETERS NECESSARY TO USE THE PACKAGE BEMOVI (INCLUDES SAMPLING PARAMETERS) --- #
# Define time points and associated sampling days
time_points = 0:4
time_points_for_ES = 1:4 #Time points for which the effect size was calculated
sampling_days = c(0, 5, 12, 19, 26)
# Define parameters used for analysing the videos in the package BEMOVI
fps = 25 # Frames per second (frame rate of the video)
seconds_per_video = 5 # Duration of each video in seconds
total_frames = fps * seconds_per_video # Total number of frames in each video
measured_volume = 34.4 # Volume measured for each video in microliters (µL)
volume_recorded_μl = measured_volume # Storing the measured volume in µL
volume_recorded_ml = volume_recorded_μl * 10**-3 # Converting the volume from µL to milliliters (mL)
pixel_to_scale = 4.05 # Conversion factor for pixels to µm
filter_min_net_disp = 25 # Minimum net displacement for an object to be considered a protist (pixels)
filter_min_duration = 1 # Minimum duration an object must be tracked to be considered a protist (seconds)
filter_detection_freq = 0.1 # Minimum frequency of detection in the video for an object to be considered a protist (detected frames / total frames)
filter_median_step_length = 3 # Minimum step length for an object to be considered a protist (pixels)
threshold_levels = c(13, 40) # Two lower pixel intensity thresholds for ImageJ to distinguish background from protists (higher threshold used for Ble)
video.description.folder = "0_video_description/" # Folder where the video descriptions (metadata about each video) are stored
video.description.file = "video_description.txt" # Filename of the text file containing the description of each video
merged_data_folder = "5_merged_data/" # Folder where the merged data files from the analysis will be stored
# Define columns that will be used for identifying species based on their movement and morphological characteristics
columns_for_species_ID = c(
"mean_grey", # Mean grayscale value (intensity) of the detected protist (brightness)
"sd_grey", # Standard deviation of the grayscale values (intensity variation)
"mean_area", # Mean area (in pixels) of the detected protist
"sd_area", # Standard deviation of the protist's area
"mean_perimeter", # Mean perimeter (length around the protist) of the detected protist
"mean_turning", # Mean turning angle of the protist's trajectory (how much the protist changes direction)
"sd_turning", # Standard deviation of the turning angles (variability in direction change)
"sd_perimeter", # Standard deviation of the protist's perimeter
"mean_major", # Mean length of the major axis of the protist (longest dimension)
"sd_major", # Standard deviation of the major axis length
"mean_minor", # Mean length of the minor axis of the protist (shortest dimension)
"sd_minor", # Standard deviation of the minor axis length
"mean_ar", # Mean aspect ratio (ratio of major to minor axis length)
"sd_ar", # Standard deviation of the aspect ratio
"duration", # Duration of time the protist is tracked in the video
"max_net", # Maximum net displacement (greatest straight-line distance traveled)
"net_disp", # Total net displacement (total straight-line distance from start to end of the trajectory)
"net_speed", # Mean net speed (speed based on net displacement)
"gross_disp", # Total gross displacement (total distance traveled including all movement)
"max_step", # Maximum step length (largest distance moved between two consecutive frames)
"min_step", # Minimum step length (smallest distance moved between two consecutive frames)
"sd_step", # Standard deviation of the step lengths (variability in frame-to-frame movement)
"sd_gross_speed", # Standard deviation of gross speed (variability in speed over time)
"max_gross_speed", # Maximum gross speed (highest speed achieved)
"min_gross_speed") # Minimum gross speed (lowest speed detected)
# --- SET PARAMETERS RELATED TO RESOURCE FLOWS --- #
resource_flow_days = c(7, 14, 21)
# --- SET PARAMETERS RELATED TO PROTISTS --- #
protist_species = c("Ble",
"Cep",
"Col",
"Eug",
"Eup",
"Lox",
"Pau",
"Pca",
"Spi",
"Spi_te",
"Tet")
protist_species_indiv_per_ml = paste0(protist_species, "_indiv_per_ml")
protist_species_bioarea_mm2_per_ml = paste0(protist_species, "_bioarea_mm2_per_ml")
protist_species_dominance = paste0(protist_species_bioarea_mm2_per_ml, "_dominance")
# --- SET PARAMETERS RELATED TO INDIVIDUALS --- #
# Initialise the dataset "ds_individuals"
ds_individuals = list()
ds_individuals_t0_extending = list()
# --- SET PARAMETERS RELATED TO ECOSYSTEMS --- #
# Initialise the dataset "ds_ecosystems_effect_size"
ds_ecosystems_effect_size = list()
# Define ecosystems to take off because of problems in the experiment
ecosystems_to_take_off = NULL
# Define the variables you want to calculate for each ecosystem
variables_ecosystems = c("bioarea_mm2_per_ml",
"log10_bioarea_mm2_per_ml",
"ln_bioarea_mm2_per_ml",
"sqrt_bioarea_mm2_per_ml",
"cbrt_bioarea_mm2_per_ml",
"sqr_bioarea_mm2_per_ml",
"bioarea_tot_mm2",
"indiv_per_ml",
"species_richness",
"shannon",
"evenness_pielou",
protist_species_indiv_per_ml,
protist_species_bioarea_mm2_per_ml,
protist_species_dominance,
"median_body_size_µm2")
# Define the levels of variables
ecosystem_size_and_trophy_ordered = c("Small autotrophic",
"Medium autotrophic",
"Large autotrophic",
"Small heterotrophic",
"Medium heterotrophic",
"Large heterotrophic")
connection_ordered = c("unconnected",
"connected")
ecosystem_types_ordered = c("Small heterotrophic unconnected",
"Small heterotrophic connected",
"Small autotrophic unconnected",
"Small autotrophic connected",
"Medium heterotrophic unconnected",
"Medium heterotrophic connected",
"Medium autotrophic unconnected",
"Medium autotrophic connected",
"Large heterotrophic unconnected",
"Large heterotrophic connected",
"Large autotrophic unconnected",
"Large autotrophic connected")
# Import the information about ecosystems
ecosystem_info = read.csv(here("1_data", "ecosystem_info.csv"), header = TRUE) %>%
rename(ecosystem_ID = culture_ID,
ecosystem_type = eco_metaeco_type,
ecosystem_size = patch_size,
ecosystem_size_ml = patch_size_ml) %>%
mutate(
# To have levels that are easier to read, transform them.
ecosystem_type = case_when(
ecosystem_type == "Sa" ~ "Small autotrophic unconnected",
ecosystem_type == "Sh" ~ "Small heterotrophic unconnected",
ecosystem_type == "Ma" ~ "Medium autotrophic unconnected",
ecosystem_type == "Mh" ~ "Medium heterotrophic unconnected",
ecosystem_type == "La" ~ "Large autotrophic unconnected",
ecosystem_type == "Lh" ~ "Large heterotrophic unconnected",
ecosystem_type == "Sa (Sa_Lh)" ~ "Small autotrophic connected",
ecosystem_type == "Sh (Sh_La)" ~ "Small heterotrophic connected",
ecosystem_type == "Ma (Ma_Mh)" ~ "Medium autotrophic connected",
ecosystem_type == "Mh (Ma_Mh)" ~ "Medium heterotrophic connected",
ecosystem_type == "La (Sh_La)" ~ "Large autotrophic connected",
ecosystem_type == "Lh (Sa_Lh)" ~ "Large heterotrophic connected",
TRUE ~ ecosystem_type),
ecosystem_type = factor(
ecosystem_type,
levels = ecosystem_types_ordered),
ecosystem_size = case_when(
ecosystem_size == "S" ~ "Small",
ecosystem_size == "M" ~ "Medium",
ecosystem_size == "L" ~ "Large",
TRUE ~ ecosystem_size),
ecosystem_size_and_trophy = factor(
x = paste(ecosystem_size, trophic_type),
levels = ecosystem_size_and_trophy_ordered),
connection = factor(
x = ifelse(metaecosystem == "yes",
"connected",
"unconnected"),
levels = connection_ordered),
metaecosystem = NULL,
metaecosystem_type = case_when(
ecosystem_size_and_trophy == "Large heterotrophic" ~ "HD",
ecosystem_size_and_trophy == "Small autotrophic" ~ "HD",
ecosystem_size_and_trophy == "Large autotrophic" ~ "AD",
ecosystem_size_and_trophy == "Small heterotrophic" ~ "AD",
ecosystem_size_and_trophy == "Medium autotrophic" ~ "ED",
ecosystem_size_and_trophy == "Medium heterotrophic" ~ "ED",
TRUE ~ metaecosystem_type),
metaecosystem_type = factor(metaecosystem_type,
levels = c("AD",
"ED",
"HD")),
metaeco_type_n_connection = if_else(
!is.na(metaecosystem_type), # Check if metaecosystem_type is not NA
paste(metaecosystem_type, connection), # Combine if not NA
NA)) # Return NA if metaecosystem_type is NA
# Find the number of ecosystems in the experiment
n_ecosystems = max(ecosystem_info$ecosystem_ID)
# Define the treatments and controls
treatments_and_controls = data.frame(treatment = c("Small autotrophic connected",
"Small heterotrophic connected",
"Medium autotrophic connected",
"Medium heterotrophic connected",
"Large autotrophic connected",
"Large heterotrophic connected"),
control = c("Small autotrophic unconnected",
"Small heterotrophic unconnected",
"Medium autotrophic unconnected",
"Medium heterotrophic unconnected",
"Large autotrophic unconnected",
"Large heterotrophic unconnected"))
n_treatments = length(unique(treatments_and_controls$treatment))
n_controls = length(unique(treatments_and_controls$control))
# Find the ID of autotrophic and heterotrophic ecosystems
ecosystem_IDs_autotrophic = ecosystem_info %>%
filter(trophic_type == "autotrophic") %>%
pull(ecosystem_ID)
ecosystem_IDs_heterotrophic = ecosystem_info %>%
filter(trophic_type == "heterotrophic") %>%
pull(ecosystem_ID)
# --- SET PARAMETERS RELATED TO META-ECOSYSTEMS --- #
# Initialise the "ds_metaecosystems" dataset
ds_metaecosystems = list()
# Define meta-ecosystems to take off because of problems in the experiment
metaecosystems_to_take_off = NULL
# Define the variables you want to calculate for each meta-ecosystem
variables_metaecos = c("total_metaecosystem_bioarea_mm2")
# Find the number of meta-ecosystems in the experiment
system_nr_metaecosystems = ecosystem_info %>%
filter(connection == "connected") %>%
pull(system_nr) %>%
unique
n_metaecosystems = length(system_nr_metaecosystems)
# Define the treatments and controls
treatments_and_controls_metaecos = data.frame(treatment = c("HD connected",
"AD connected",
"ED connected"),
control = c("HD unconnected",
"AD unconnected",
"ED unconnected"))
n_treatments_metaecos = length(unique(treatments_and_controls_metaecos$treatment))
n_controls_metaecos = length(unique(treatments_and_controls_metaecos$control))
# --- SET PARAMETERS FOR PLOTTING --- #
# Set line colours
treatment_colours = c("AD" = "#5ab4ac",
"ED" = "#969696",
"HD" = "#d8b365",
"HD connected" = "#CB4335",
"AD connected" = "#6C3483",
"ED connected" = "black",
"HD unconnected" = "#CB4335",
"AD unconnected" = "#6C3483",
"ED unconnected" = "black",
"Small heterotrophic" = "#c6dbef",
"Medium heterotrophic" = "#3182bd",
"Large heterotrophic" = "#08306b",
"Small autotrophic" = "#c7e9c0",
"Medium autotrophic" = "#2ca25f",
"Large autotrophic" = "#00441b",
"Small heterotrophic unconnected" = "#deebf7",
"Small heterotrophic connected" = "#deebf7",
"Medium heterotrophic unconnected" = "#9ecae1",
"Medium heterotrophic connected" = "#9ecae1",
"Large heterotrophic unconnected" = "#3182bd",
"Large heterotrophic connected" = "#3182bd",
"Small autotrophic unconnected" = "#ccece6",
"Small autotrophic connected" = "#ccece6",
"Medium autotrophic unconnected" = "#99d8c9",
"Medium autotrophic connected" = "#99d8c9",
"Large autotrophic unconnected" = "#2ca25f",
"Large autotrophic connected" = "#2ca25f")
# Set line types
treatment_linetypes = c("connected" = "solid",
"unconnected" = "longdash")
# Set figure height and width in the RMD output
figures_width_rmd_output = 10
figures_height_rmd_output = 7
# Set parameters legend
legend_position = "top"
legend_width_cm = 2
size_legend = 12
# Set parameters boxplots
boxplot_width = 2
# Set parameters points & error bars
treatment_points_size = 2.5
width_errorbar = 0.2
dodging_error_bar = 0.5
dodging = 0.5
# Set parameters lines
treatment_lines_linewidth = 1
# Set parameters resource flow line (vertical line indicating the days of the resource flow)
resource_flow_line_type = "solid"
resource_flow_line_colour = "#d9d9d9"
resource_flow_line_width = 0.3
# Set parameters of the horizontal line crossing zero
zero_line_colour = "grey"
zero_line_line_type = "dotted"
zero_line_line_width = 0.5
zero_line_ES_line_type = "dotted"
zero_line_ES_colour = "grey"
zero_line_ES_line_width = 1
# Set parameters of the package "ggarrange" which combines multiple ggplots
ggarrange_margin_top = 0
ggarrange_margin_bottom = 0
ggarrange_margin_left = 0
ggarrange_margin_right = 0
# Set parameters of the figures saved for the paper
paper_width = 17.3
paper_height = 20
paper_units = "cm"
paper_res = 600
paper_labels_size = 12
# Set parameters of the figures saved for presentations
presentation_figure_size = 15
presentation_figure_width = 30
presentation_figure_height = 22
presentation_labels_size = 24
presentation_treatment_points_size = 5
presentation_treatment_linewidth = 2
presentation_figure_units = "cm"
presentation_figure_res = 600
# Set parameters for the grey background used to show the time points excluded from the analysis
grey_background_xmin = -Inf
grey_background_xmax = 11.5
grey_background_ymin = -Inf
grey_background_ymax = Inf
grey_background_fill = "#f0f0f0"
grey_background_alpha = 0.03
grey_background_color = "transparent"
# Set parameters axes
size_x_axis = 16
size_y_axis = 14
axis_names = data.frame(variable = NA,
axis_name = NA) %>%
add_row(variable = "day", axis_name = "Time (day)") %>%
add_row(variable = "ecosystem_size_ml", axis_name = "Ecosystem Size (ml)") %>%
add_row(variable = "total_metaecosystem_bioarea_mm2", axis_name = "Total Biomass (mm2)") %>%
add_row(variable = "bioarea_mm2_per_ml", axis_name = "Biomass (mm2/ml)") %>%
add_row(variable = "bioarea_mm2_per_ml_d", axis_name = "Effect Size of Bioarea Density") %>%
add_row(variable = "log10_bioarea_mm2_per_ml", axis_name = "Log10 Biomass (mm2/ml)") %>%
add_row(variable = "ln_bioarea_mm2_per_ml", axis_name = "Ln Biomass (mm2/ml)") %>%
add_row(variable = "sqrt_bioarea_mm2_per_ml", axis_name = "Sqrt Biomass (mm2/ml)") %>%
add_row(variable = "indiv_per_ml", axis_name = "Abundance (ind/ml)") %>%
add_row(variable = "indiv_per_ml_d", axis_name = "Effect Size of Abundance") %>%
add_row(variable = "species_richness", axis_name = "Species Richness") %>%
add_row(variable = "species_richness_d", axis_name = "Effect Size of Species Richness") %>%
add_row(variable = "shannon", axis_name = "Shannon Index") %>%
add_row(variable = "shannon_d", axis_name = "Effect Size of Shannon Index") %>%
add_row(variable = "evenness_pielou", axis_name = "Evenness (Pielou's Index)") %>%
add_row(variable = "evenness_pielou_d", axis_name = "Effect Size of Evenness") %>%
add_row(variable = "median_body_size_µm2", axis_name = "Median Body Size (µm2)") %>%
add_row(variable = "median_body_size_µm2_d", axis_name = "Effect Size of Median Body Size") %>%
add_row(variable = "Ble_indiv_per_ml", axis_name = "Ble Density (ind/ml)") %>%
add_row(variable = "Cep_indiv_per_ml", axis_name = "Cep Density (ind/ml)") %>%
add_row(variable = "Col_indiv_per_ml", axis_name = "Col Density (ind/ml)") %>%
add_row(variable = "Eug_indiv_per_ml", axis_name = "Eug Density (ind/ml)") %>%
add_row(variable = "Eup_indiv_per_ml", axis_name = "Eup Density (ind/ml)") %>%
add_row(variable = "Lox_indiv_per_ml", axis_name = "Lox Density (ind/ml)") %>%
add_row(variable = "Pau_indiv_per_ml", axis_name = "Pau Density (ind/ml)") %>%
add_row(variable = "Pca_indiv_per_ml", axis_name = "Pca Density (ind/ml)") %>%
add_row(variable = "Spi_indiv_per_ml", axis_name = "Spi Density (ind/ml)") %>%
add_row(variable = "Spi_te_indiv_per_ml", axis_name = "Spi te Density (ind/ml)") %>%
add_row(variable = "Tet_indiv_per_ml", axis_name = "Tet Density (ind/ml)") %>%
add_row(variable = "Ble_indiv_per_ml_d", axis_name = "Effect Size of Ble Density") %>%
add_row(variable = "Cep_indiv_per_ml_d", axis_name = "Effect Size of Cep Density") %>%
add_row(variable = "Col_indiv_per_ml_d", axis_name = "Effect Size of Col Density") %>%
add_row(variable = "Eug_indiv_per_ml_d", axis_name = "Effect Size of Eug Density") %>%
add_row(variable = "Eup_indiv_per_ml_d", axis_name = "Effect Size of Eup Density") %>%
add_row(variable = "Lox_indiv_per_ml_d", axis_name = "Effect Size of Lox Density") %>%
add_row(variable = "Pau_indiv_per_ml_d", axis_name = "Effect Size of Pau Density") %>%
add_row(variable = "Pca_indiv_per_ml_d", axis_name = "Effect Size of Pca Density") %>%
add_row(variable = "Spi_indiv_per_ml_d", axis_name = "Effect Size of Spi Density") %>%
add_row(variable = "Spi_te_indiv_per_ml_d", axis_name = "Effect Size of Spi te Density") %>%
add_row(variable = "Tet_indiv_per_ml_d", axis_name = "Effect Size of Tet Density") %>%
add_row(variable = "dominance", axis_name = "Dominance (%)") %>%
add_row(variable = "Ble_indiv_per_ml_dominance", axis_name = "Ble Dominance (%)") %>%
add_row(variable = "Cep_indiv_per_ml_dominance", axis_name = "Cep Dominance (%)") %>%
add_row(variable = "Col_indiv_per_ml_dominance", axis_name = "Col Dominance (%)") %>%
add_row(variable = "Eug_indiv_per_ml_dominance", axis_name = "Eug Dominance (%)") %>%
add_row(variable = "Eup_indiv_per_ml_dominance", axis_name = "Eup Dominance (%)") %>%
add_row(variable = "Lox_indiv_per_ml_dominance", axis_name = "Lox Dominance (%)") %>%
add_row(variable = "Pau_indiv_per_ml_dominance", axis_name = "Pau Dominance (%)") %>%
add_row(variable = "Pca_indiv_per_ml_dominance", axis_name = "Pca Dominance (%)") %>%
add_row(variable = "Spi_indiv_per_ml_dominance", axis_name = "Spi Dominance (%)") %>%
add_row(variable = "Spi_te_indiv_per_ml_dominance", axis_name = "Spi te Dominance (%)") %>%
add_row(variable = "Tet_indiv_per_ml_dominance", axis_name = "Tet Dominance (%)") %>%
add_row(variable = "Ble_indiv_per_ml_dominance_d", axis_name = "Effect Size of Ble Dominance") %>%
add_row(variable = "Cep_indiv_per_ml_dominance_d", axis_name = "Effect Size of Cep Dominance") %>%
add_row(variable = "Col_indiv_per_ml_dominance_d", axis_name = "Effect Size of Col Dominance") %>%
add_row(variable = "Eug_indiv_per_ml_dominance_d", axis_name = "Effect Size of Eug Dominance") %>%
add_row(variable = "Eup_indiv_per_ml_dominance_d", axis_name = "Effect Size of Eup Dominance") %>%
add_row(variable = "Lox_indiv_per_ml_dominance_d", axis_name = "Effect Size of Lox Dominance") %>%
add_row(variable = "Pau_indiv_per_ml_dominance_d", axis_name = "Effect Size of Pau Dominance") %>%
add_row(variable = "Pca_indiv_per_ml_dominance_d", axis_name = "Effect Size of Pca Dominance") %>%
add_row(variable = "Sp_indiv_per_mli_dominance_d", axis_name = "Effect Size of Spi Dominance") %>%
add_row(variable = "Spi_te_indiv_per_ml_dominance_d", axis_name = "Effect Size of Spi te Dominance") %>%
add_row(variable = "Tet_indiv_per_ml_dominance_d", axis_name = "Effect Size of Tet Dominance") %>%
add_row(variable = "log_size_class", axis_name = "Log Size (μm2)") %>%
add_row(variable = "class_indiv_per_µl", axis_name = "Density (ind/ml)") %>%
add_row(variable = "median_body_area_µm2", axis_name = "Median Body Size (µm²)") %>%
add_row(variable = "median_body_area_µm2_d", axis_name = "Effect Size of Median Body Size") %>%
slice(-1)
# --- SET PARAMETERS FOR MODELLING --- #
# Decide which time points you want to include in the analysis. We chose the
# first time point as 2 because it's after the first disturbance.
time_points_model = 2:4
# Decide optimizers for mixed effect models
optimizer_input = 'Nelder_Mead'
method_input = ''
# --- SET PARAMETERS FOR DISPLAYING THE RESULTS --- #
#iterated_results_table = list()
# results_table_ecos = data.frame(
#
# response_variable = "Just to create the column",
# trophy = "Just to create the column",
#
# anova_interact_sum_sq = "Just to create the column",
# anova_interact_mean_sq = "Just to create the column",
# anova_interact_NumDF = "Just to create the column",
# anova_interact_DenDF = "Just to create the column",
# anova_interact_F = "Just to create the column",
# anova_interact_ChiSq = "Just to create the column",
# anova_interact_df = "Just to create the column",
# anova_interact_p = "Just to create the column",
#
# S_connection_estimate = "Just to create the column",
# S_connection_SE = "Just to create the column",
# S_connection_df = "Just to create the column",
# S_connection_t = "Just to create the column",
# S_connection_p = "Just to create the column",
#
# M_connection_estimate = "Just to create the column",
# M_connection_SE = "Just to create the column",
# M_connection_df = "Just to create the column",
# M_connection_t = "Just to create the column",
# M_connection_p = "Just to create the column",
#
# L_connection_estimate = "Just to create the column",
# L_connection_SE = "Just to create the column",
# L_connection_df = "Just to create the column",
# L_connection_t = "Just to create the column",
# L_connection_p = "Just to create the column",
#
# M_vs_S_unc_estimate = "Just to create the column",
# M_vs_S_unc_SE = "Just to create the column",
# M_vs_S_unc_df = "Just to create the column",
# M_vs_S_unc_t = "Just to create the column",
# M_vs_S_unc_p = "Just to create the column",
#
# L_vs_S_unc_estimate = "Just to create the column",
# L_vs_S_unc_SE = "Just to create the column",
# L_vs_S_unc_df = "Just to create the column",
# L_vs_S_unc_t = "Just to create the column",
# L_vs_S_unc_p = "Just to create the column") %>%
#
# slice(-1)
# # results_table_metaecos = data.frame(
# #
# # response_variable = "Just to create the column",
# #
# # anova_interact_sum_sq = "Just to create the column",
# # anova_interact_mean_sq = "Just to create the column",
# # anova_interact_NumDF = "Just to create the column",
# # anova_interact_DenDF = "Just to create the column",
# # anova_interact_F = "Just to create the column",
# # anova_interact_ChiSq = "Just to create the column",
# # anova_interact_df = "Just to create the column",
# # anova_interact_p = "Just to create the column",
# #
# # AD_connection_estimate = "Just to create the column",
# # AD_connection_SE = "Just to create the column",
# # AD_connection_df = "Just to create the column",
# # AD_connection_t = "Just to create the column",
# # AD_connection_p = "Just to create the column",
# #
# # ED_connection_estimate = "Just to create the column",
# # ED_connection_SE = "Just to create the column",
# # ED_connection_df = "Just to create the column",
# # ED_connection_t = "Just to create the column",
# # ED_connection_p = "Just to create the column",
# #
# # HD_connection_estimate = "Just to create the column",
# # HD_connection_SE = "Just to create the column",
# # HD_connection_df = "Just to create the column",
# # HD_connection_t = "Just to create the column",
# # HD_connection_p = "Just to create the column",
# #
# # AD_vs_ED_conn_estimate = "Just to create the column",
# # AD_vs_ED_conn_SE = "Just to create the column",
# # AD_vs_ED_conn_df = "Just to create the column",
# # AD_vs_ED_conn_t = "Just to create the column",
# # AD_vs_ED_conn_p = "Just to create the column",
# #
# # HD_vs_ED_conn_estimate = "Just to create the column",
# # HD_vs_ED_conn_SE = "Just to create the column",
# # HD_vs_ED_conn_df = "Just to create the column",
# # HD_vs_ED_conn_t = "Just to create the column",
# # HD_vs_ED_conn_p = "Just to create the column") %>%
# #
# # slice(-1)
#
# digits_p = 3
# digits_F = 3
# digits_NumDF = 0
# digits_DenDF = 0
# digits_sum_sq = 1
# digits_mean_sq = 1
# digits_estimate = 2
# digits_SE = 2
# digits_Chisq = 1
# digits_df = 1
ds_individuals)# --- IMPORT DATASETS --- #
# Loop through time points to import them and modify them
for(time_point in time_points){
# Note: We use time_point + 1 for 1-based indexing in R.
ds_individuals[[time_point + 1]] = read.csv(here("1_data",
paste0(
"13_threshold_analysis_t",
time_point,
".csv"))) %>%
mutate(comment = NULL,
# To remember that some videos are replicates of the same ecosystem
# at a time point, introduce the column video_replicate. For all time
# points other than time point 0, it should be 1, as at each time
# point only a single video has been taken for each ecosystem. For
# time point 0, assign the value of file, which is the number of
# video that had been taken.
video_replicate = ifelse(time_point > 0,
yes = as.character(1),
no = as.character(file)),
# To know which ecosystem was filmed, assign to ecosystem ID the
# value of file, as ecosystems were filmed in numerical order.
# Assign NA to videos at time point 0 because we filmed the master
# bottles of autotrophic and heterotrophic ecosystems and not the
# single ecosystems.
ecosystem_ID = ifelse(time_point > 0,
yes = as.character(file),
no = as.character(NA)),
# Derive biomass information
bioarea_µm2 = mean_area,
bioarea_mm2 = bioarea_µm2 * 10^-6,
bioarea_mm2_per_ml = bioarea_mm2 / volume_recorded_ml,
bioarea_mm2_per_frame_per_ml = bioarea_mm2_per_ml * N_frames /
total_frames) %>%
# To tidy up, reorder columns.
select(time_point,
day,
video_replicate,
file,
id,
everything())
}
# --- EXTEND T0 --- #
# Assign to every ecosystem the videos of its trophic type at time point 0.
for(ID in 1:n_ecosystems){
ds_individuals_t0_extending[[ID]] = ds_individuals[[1]] %>%
# To allocate the autotrophic videos to autotrophic ecosystems and the
# heterotrophic videos to heterotrophic ecosystems, choose autotrophic
# videos for autotrophic ecosystems and heterotrophic videos for
# heterotrophic ecosystems.
filter(
(ID %in% ecosystem_IDs_autotrophic & trophic_type == "autotrophic") |
(ID %in% ecosystem_IDs_heterotrophic & trophic_type == "heterotrophic")) %>%
# To have more informative columns, manipulate them.
mutate(file = as.character(str_extract(file, "\\d+")),
ecosystem_ID = as.character(ID),
# To know that different individuals belong to different videos, add the
# column video replicates. The autotrophic videos start from video 1.
# The heterotrophic videos start from video 7.
video_replicate = as.character(file)) %>%
# To tidy up, reorder columns.
select(time_point,
day,
ecosystem_ID,
video_replicate,
file,
id,
everything())
}
# --- BIND EVERYTHING TOGETHER --- #
ds_individuals[[1]] = ds_individuals_t0_extending %>%
bind_rows()
ds_individuals = ds_individuals %>%
bind_rows()
# --- FINISH UP DS_INDIVIDUALS --- #
ds_individuals = ds_individuals %>%
mutate(
# To avoid that trophic_type gives problems when combining ds_individuals with
# ecosystem_info, get rid of it, as it had the right value only at time
# point 0.
trophic_type = NULL,
# To better work with ecosystem_ID, video_replicate, and file columns,
# transform them into a double format.
ecosystem_ID = as.double(str_extract(ecosystem_ID, "\\d+")),
video_replicate = as.double(str_extract(video_replicate, "\\d+")),
file = as.double(str_extract(file, "\\d+"))) %>%
# To have all the information on the ecosystems that were not in the original
# data, bind 'ds_individuals' with 'ecosystem_info'.
left_join(ecosystem_info,
by = "ecosystem_ID") %>%
# To tidy up, reorder columns.
select(time_point,
day,
video_replicate,
ecosystem_ID,
system_nr,
ecosystem_type,
ecosystem_size,
ecosystem_size_ml,
trophic_type,
ecosystem_size_and_trophy,
metaecosystem_type,
connection,
metaeco_type_n_connection,
bioarea_mm2,
bioarea_mm2_per_frame_per_ml,
N_frames,
all_of(columns_for_species_ID))
# --- CREATE TRAINING DATASET --- #
# Create a dataset excluding the species "Ble" for threshold 13.
# This is necessary because at threshold 13, we could not eliminate
# the food source (Chi) for "Ble".
training_individuals_13 = read.csv(here("1_data",
"13_threshold_analysis_training.csv")) %>%
# To make it easier to handle the level, transform Spi te into Spi_te.
mutate(species = case_when(species == "Spi te " ~ "Spi_te",
TRUE ~ species)) %>%
# To tidy up, reorder columns.
select(file,
id,
species,
N_frames,
mean_area,
everything()) %>%
filter(species != "Ble")
# Create a dataset including only the species "Ble" for threshold 40.
# At threshold 40, we successfully eliminated the food source (Chi)
# for "Ble", allowing for its inclusion in the analysis.
training_individuals_40 = read.csv(here("1_data",
"40_threshold_analysis_training.csv")) %>%
# To tidy up, reorder columns.
select(file,
id,
species,
N_frames,
mean_area,
everything()) %>%
filter(species == "Ble")
# Bind the two previous datasets
training_individuals = rbind(training_individuals_13,
training_individuals_40)
# --- CREATE PREDICTIVE MODEL --- #
# See where we previously set the parameters for a description of these variables.
species_ID_model = svm(factor(species) ~
mean_grey +
sd_grey +
mean_area +
sd_area +
mean_perimeter +
mean_turning +
sd_turning +
sd_perimeter +
mean_major +
sd_major +
mean_minor +
sd_minor +
mean_ar +
sd_ar +
duration +
max_net +
net_disp +
net_speed +
gross_disp +
max_step +
min_step +
sd_step +
sd_gross_speed +
max_gross_speed +
min_gross_speed ,
data = training_individuals,
probability = T,
na.action = na.pass)
# --- SHOW CONFUSION MATRIX --- #
# Create a confusion matrix comparing the fitted species predictions from the
# SVM model with the actual species labels from the training dataset.
confusion_matrix = table(species_ID_model$fitted, training_individuals$species)
# Create a copy of the confusion matrix to modify for error calculation.
confusion_matrix_with_diagonal_zeros = confusion_matrix
# Set the diagonal elements (true positives) to zero for error calculation.
# This allows us to compute the misclassification errors without counting the
# correct classifications.
diag(confusion_matrix_with_diagonal_zeros) = 0
# Calculate the class error for each species.
# Class error is defined as the ratio of misclassified samples to the total
# samples for each species.
confusion_matrix = cbind(
confusion_matrix,
class_error = rowSums(confusion_matrix_with_diagonal_zeros) /
rowSums(confusion_matrix)) %>%
as.data.frame() %>%
mutate(class_error_percentage = class_error * 100,
class_error = NULL)
# Display the final confusion matrix with class errors as a data frame.
confusion_matrix
## Ble Cep Col Eug Eup Lox Pau Pca Spi Spi_te Tet class_error_percentage
## Ble 115 0 0 0 0 0 0 0 3 2 0 4.1666667
## Cep 1 129 0 0 4 5 8 1 10 2 0 19.3750000
## Col 0 0 291 0 1 1 2 0 2 0 0 2.0202020
## Eug 1 0 0 576 1 0 0 0 25 3 16 7.3954984
## Eup 0 0 0 0 113 0 2 0 0 0 0 1.7391304
## Lox 0 0 0 0 5 169 1 0 0 0 0 3.4285714
## Pau 4 0 0 0 2 0 94 2 0 0 0 7.8431373
## Pca 0 0 0 0 1 0 0 148 0 0 0 0.6711409
## Spi 4 3 2 0 0 0 1 5 238 0 1 6.2992126
## Spi_te 0 0 0 0 0 0 0 0 0 107 0 0.0000000
## Tet 2 0 0 0 0 5 0 0 3 1 137 7.4324324
# --- ID SPECIES --- #
species_vector = ds_individuals %>%
select(trophic_type, mean_grey:min_gross_speed) %>%
mutate(species = as.character(predict(object = species_ID_model,
.,
type = "response")),
# Given that autotrophic ecosystems are exclusively composed of
# Euglena gracilis (Eug), we can simply designate Eug as the species
# for each individual in autotrophic ecosystems.
species = ifelse(trophic_type == "autotrophic",
"Eug",
species)) %>%
select(species)
ds_individuals = cbind(ds_individuals, species_vector)
ds_ecosystems)# --- SUMMARISE ECOSYSTEM-LEVEL METRICS --- #
ds_ecosystems = ds_individuals %>%
#Summarise for each species their bioarea and nr of individuals
group_by_at(vars(time_point:metaeco_type_n_connection,
species)) %>%
summarise(bioarea_mm2_per_ml = sum(bioarea_mm2_per_frame_per_ml),
indiv_per_ml = sum(N_frames) / total_frames,
median_body_size_mm2 = median(bioarea_mm2),
median_body_size_µm2 = median_body_size_mm2 * 10^6) %>%
# Go from long to wide format
pivot_wider(names_from = species,
values_from = c(bioarea_mm2_per_ml,
indiv_per_ml)) %>%
# Rename the resulting columns for clarity
rename(Ble_indiv_per_ml = indiv_per_ml_Ble,
Cep_indiv_per_ml = indiv_per_ml_Cep,
Col_indiv_per_ml = indiv_per_ml_Col,
Eug_indiv_per_ml = indiv_per_ml_Eug,
Eup_indiv_per_ml = indiv_per_ml_Eup,
Lox_indiv_per_ml = indiv_per_ml_Lox,
Pau_indiv_per_ml = indiv_per_ml_Pau,
Pca_indiv_per_ml = indiv_per_ml_Pca,
Spi_indiv_per_ml = indiv_per_ml_Spi,
Spi_te_indiv_per_ml = indiv_per_ml_Spi_te,
Tet_indiv_per_ml = indiv_per_ml_Tet,
Ble_bioarea_mm2_per_ml = bioarea_mm2_per_ml_Ble,
Cep_bioarea_mm2_per_ml = bioarea_mm2_per_ml_Cep,
Col_bioarea_mm2_per_ml = bioarea_mm2_per_ml_Col,
Eug_bioarea_mm2_per_ml = bioarea_mm2_per_ml_Eug,
Eup_bioarea_mm2_per_ml = bioarea_mm2_per_ml_Eup,
Lox_bioarea_mm2_per_ml = bioarea_mm2_per_ml_Lox,
Pau_bioarea_mm2_per_ml = bioarea_mm2_per_ml_Pau,
Pca_bioarea_mm2_per_ml = bioarea_mm2_per_ml_Pca,
Spi_bioarea_mm2_per_ml = bioarea_mm2_per_ml_Spi,
Spi_te_bioarea_mm2_per_ml = bioarea_mm2_per_ml_Spi_te,
Tet_bioarea_mm2_per_ml = bioarea_mm2_per_ml_Tet) %>%
# Average across videos and calculate metrics. Do that to have a single
# value at time point 0.
group_by_at(vars(time_point:metaeco_type_n_connection)) %>%
summarise(across(contains("bioarea_mm2_per_ml"),
sum,
na.rm = TRUE),
across(contains("indiv_per_ml"),
sum,
na.rm = TRUE),
median_body_size_µm2 = mean(median_body_size_µm2)) %>%
# Calculate ecosystem-level metrics
mutate(
# Calculate biomass and individuals of ecosystems.
bioarea_mm2_per_ml = sum(across(contains("bioarea_mm2_per_ml"))),
bioarea_tot_mm2 = bioarea_mm2_per_ml * ecosystem_size_ml,
indiv_per_ml = sum(across(contains("indiv_per_ml"))),
# Transform species densities from NA to 0
across(all_of(protist_species_indiv_per_ml), ~ replace_na(., 0)),
across(all_of(protist_species_bioarea_mm2_per_ml), ~ replace_na(., 0)),
# Calculate biodiversity of ecosystems
species_richness = specnumber(across(ends_with("_indiv_per_ml"))),
shannon = diversity(across(ends_with("_bioarea_mm2_per_ml")),
index = "shannon"),
shannon = ifelse(species_richness == 0,
yes = NA,
no = shannon),
evenness_pielou = shannon / log(species_richness),
# Calculate species dominance
across(all_of(protist_species_indiv_per_ml),
~ (.x / indiv_per_ml) * 100,
.names = "{.col}_dominance"),
across(all_of(protist_species_bioarea_mm2_per_ml),
~ (.x / indiv_per_ml) * 100,
.names = "{.col}_dominance"),
# Do transformations
log10_bioarea_mm2_per_ml = log10(bioarea_mm2_per_ml),
ln_bioarea_mm2_per_ml = log(bioarea_mm2_per_ml),
sqrt_bioarea_mm2_per_ml = sqrt(bioarea_mm2_per_ml),
cbrt_bioarea_mm2_per_ml = bioarea_mm2_per_ml^(1/3),
sqr_bioarea_mm2_per_ml = bioarea_mm2_per_ml^(2)) %>%
# To have a single value for each ecosystem at a time point, average video replicates.
group_by(across(all_of(c("time_point",
"day",
"system_nr",
"ecosystem_ID",
"metaecosystem_type",
"ecosystem_type",
"ecosystem_size",
"ecosystem_size_ml",
"trophic_type",
"ecosystem_size_and_trophy",
"connection",
"metaeco_type_n_connection")))) %>%
summarise(across(contains("_per_ml"), mean),
across(contains("tot"), mean),
species_richness = mean(species_richness),
shannon = mean(shannon),
evenness_pielou = mean(evenness_pielou),
median_body_size_µm2 = mean(median_body_size_µm2)) %>%
ungroup() %>%
# To tidy up, select useful columns.
select(time_point,
day,
system_nr,
ecosystem_ID,
metaecosystem_type,
metaeco_type_n_connection,
ecosystem_type,
ecosystem_size,
ecosystem_size_ml,
trophic_type,
connection,
ecosystem_size_and_trophy,
bioarea_mm2_per_ml,
log10_bioarea_mm2_per_ml,
ln_bioarea_mm2_per_ml,
sqrt_bioarea_mm2_per_ml,
cbrt_bioarea_mm2_per_ml,
sqr_bioarea_mm2_per_ml,
bioarea_tot_mm2,
indiv_per_ml,
species_richness,
shannon,
evenness_pielou,
median_body_size_µm2,
any_of(protist_species_bioarea_mm2_per_ml),
any_of(protist_species_indiv_per_ml),
any_of(protist_species_dominance))
## Warning: There was 1 warning in `summarise()`.
## ℹ In argument: `across(contains("bioarea_mm2_per_ml"), sum, na.rm = TRUE)`.
## ℹ In group 1: `time_point = 0`, `day = 0`, `video_replicate = 1`, `ecosystem_ID
## = 1`, `system_nr = 1`, `ecosystem_type = Small autotrophic unconnected`,
## `ecosystem_size = "Small"`, `ecosystem_size_ml = 7.5`, `trophic_type =
## "autotrophic"`, `ecosystem_size_and_trophy = Small autotrophic`,
## `metaecosystem_type = HD`, `connection = unconnected`,
## `metaeco_type_n_connection = "HD unconnected"`.
## Caused by warning:
## ! The `...` argument of `across()` is deprecated as of dplyr 1.1.0.
## Supply arguments directly to `.fns` through an anonymous function instead.
##
## # Previously
## across(a:b, mean, na.rm = TRUE)
##
## # Now
## across(a:b, \(x) mean(x, na.rm = TRUE))
ds_dominances_with_CI)Get ds_dominances_with_CI with all the mean and 95 % CI dominance of all the species.
# To be able to plot dominance for multiple species, get their mean, upper boundary, and lower boundary in a long format.
dominances_mean = ds_ecosystems %>%
group_by(day, time_point, ecosystem_type) %>%
reframe(Ble = mean(Ble_bioarea_mm2_per_ml_dominance, na.rm = TRUE),
Cep = mean(Cep_bioarea_mm2_per_ml_dominance, na.rm = TRUE),
Col = mean(Col_bioarea_mm2_per_ml_dominance, na.rm = TRUE),
Eug = mean(Eug_bioarea_mm2_per_ml_dominance, na.rm = TRUE),
Eup = mean(Eup_bioarea_mm2_per_ml_dominance, na.rm = TRUE),
Lox = mean(Lox_bioarea_mm2_per_ml_dominance, na.rm = TRUE),
Pau = mean(Pau_bioarea_mm2_per_ml_dominance, na.rm = TRUE),
Pca = mean(Pca_bioarea_mm2_per_ml_dominance, na.rm = TRUE),
Spi = mean(Spi_bioarea_mm2_per_ml_dominance, na.rm = TRUE),
Spi_te = mean(Spi_te_bioarea_mm2_per_ml_dominance, na.rm = TRUE),
Tet = mean(Tet_bioarea_mm2_per_ml_dominance, na.rm = TRUE)) %>%
pivot_longer(cols = -c("day", "time_point", "ecosystem_type"),
names_to = "species",
values_to = "mean_dominance")
dominances_lower = ds_ecosystems %>%
group_by(day, time_point, ecosystem_type) %>%
reframe(Ble = quantile(Ble_bioarea_mm2_per_ml_dominance, probs = 0.025, na.rm = TRUE),
Cep = quantile(Cep_bioarea_mm2_per_ml_dominance, probs = 0.025, na.rm = TRUE),
Col = quantile(Col_bioarea_mm2_per_ml_dominance, probs = 0.025, na.rm = TRUE),
Eug = quantile(Eug_bioarea_mm2_per_ml_dominance, probs = 0.025, na.rm = TRUE),
Eup = quantile(Eup_bioarea_mm2_per_ml_dominance, probs = 0.025, na.rm = TRUE),
Lox = quantile(Lox_bioarea_mm2_per_ml_dominance, probs = 0.025, na.rm = TRUE),
Pau = quantile(Pau_bioarea_mm2_per_ml_dominance, probs = 0.025, na.rm = TRUE),
Pca = quantile(Pca_bioarea_mm2_per_ml_dominance, probs = 0.025, na.rm = TRUE),
Spi = quantile(Spi_bioarea_mm2_per_ml_dominance, probs = 0.025, na.rm = TRUE),
Spi_te = quantile(Spi_te_bioarea_mm2_per_ml_dominance, probs = 0.025, na.rm = TRUE),
Tet = quantile(Tet_bioarea_mm2_per_ml_dominance, probs = 0.025, na.rm = TRUE)) %>%
pivot_longer(cols = -c("day", "time_point", "ecosystem_type"),
names_to = "species",
values_to = "lower_95_CI")
dominances_upper = ds_ecosystems %>%
group_by(day, time_point, ecosystem_type) %>%
reframe(Ble = quantile(Ble_bioarea_mm2_per_ml_dominance, probs = 0.975, na.rm = TRUE),
Cep = quantile(Cep_bioarea_mm2_per_ml_dominance, probs = 0.975, na.rm = TRUE),
Col = quantile(Col_bioarea_mm2_per_ml_dominance, probs = 0.975, na.rm = TRUE),
Eug = quantile(Eug_bioarea_mm2_per_ml_dominance, probs = 0.975, na.rm = TRUE),
Eup = quantile(Eup_bioarea_mm2_per_ml_dominance, probs = 0.975, na.rm = TRUE),
Lox = quantile(Lox_bioarea_mm2_per_ml_dominance, probs = 0.975, na.rm = TRUE),
Pau = quantile(Pau_bioarea_mm2_per_ml_dominance, probs = 0.975, na.rm = TRUE),
Pca = quantile(Pca_bioarea_mm2_per_ml_dominance, probs = 0.975, na.rm = TRUE),
Spi = quantile(Spi_bioarea_mm2_per_ml_dominance, probs = 0.975, na.rm = TRUE),
Spi_te = quantile(Spi_te_bioarea_mm2_per_ml_dominance, probs = 0.975, na.rm = TRUE),
Tet = quantile(Tet_bioarea_mm2_per_ml_dominance, probs = 0.975, na.rm = TRUE)) %>%
pivot_longer(cols = -c("day", "time_point", "ecosystem_type"),
names_to = "species",
values_to = "upper_95_CI")
ds_dominances_with_CI = reduce(list(dominances_mean,
dominances_lower,
dominances_upper),
full_join,
by = NULL)
ds_ecosystems_effect_size)To analyse how strong the effects of the connection on the biomass,
biodiversity, and population densities within ecosystems were, we want
to compile a dataset (ds_ecosystems_effect_size) where each
row represents the effect size of a connected vs unconnected ecosystem
type (e.g., small autotrophic connected vs unconnected) at a time point.
If the 95% CI of the effect size crosses the zero line it means that it
is statistically significant. We use the effect size Hedge’s d (aka
Hedge’s g), as it can handle the treatment and/or control equal to zero
(log response ratio cannot: ln(treatment/0) = Inf; ln(0/control) = -inf;
ln(0/0) = Nan), small sample sizes (“it works well when there are as
few as five to ten studies”, @Rosenberg2013), and unequal variance between
treatment and control ([@Rosenberg2013]).
Hedge’s d (d) is the difference in mean between treatment and control
divided by by their weighted spread (denominator) multiplied by a factor
(J) that controls for small sample sizes [@Rosenberg2013]. The 95% confidence interval of
Hedge’s d is calculated from its standard error (SE) as [@Hedges1985] \(d ±
1.96 * SE\) where the standard error is calculated as show in
@Borenstein2009.
We calculate Hedge’s d and its 95 % confidence interval in three steps. (1) Calculate means, standard deviations and sample sizes. Calculate the mean of the treatment (Y1) and control (Y2), the standard deviation of the treatment (s1) and the control (s2), as well as the sample size of the treatment (n1) and the control (n2) at each time point and for each response variable. (2) Calculate Hedge’s d. Use means, standard deviations and sample sizes to calculate effect sizes. (3) Retain only the treatments (connected ecosystems), discarding the controls (unconnected). This is because we calculated the effect size of only connected compared to unconnected and not the other way around.
\[ d = \frac{Y1 - Y2}{denominator} * J \]
\[ denominator = \sqrt{\frac{(n_1-1)*s_1^2 + (n_2 - 1) * s_2^2}{n_1 + n_2 - 2}} \]
\[ J = 1 - \frac{3}{(4 * (n_1 + n_2 - 2)) - 1} \]
\[ SE = \sqrt{J^2 * \frac{n_1 + n_2}{n_1*n_2} + \frac{d^2}{2*(n_1 + n_2)}} \]
## - (1) Calculate means, standard deviations and sample sizes. - ##
for (variable in 1:length(variables_ecosystems)) {
ds_ecosystems_effect_size[[variable]] = ds_ecosystems %>%
filter(
# To have a cleaner dataset filter out time point 0, as ecosystems were assumed to be the same as the bottles from which they were started, as we only measured these bottles and not the ecosystems.
time_point != 0,
# To have a cleaner dataset filter out ecosystems in which this variable could not be computed (e.g., species richness of a crashed culture).
!is.na(!!sym(variables_ecosystems[variable]))) %>%
# To afterwards calculate effect sizes, get the mean, sd, and sample size of treatments at each time point
group_by(across(all_of(c("time_point",
"day",
"ecosystem_type",
"ecosystem_size_and_trophy",
"connection",
"ecosystem_size",
"ecosystem_size_ml",
"trophic_type",
"metaecosystem_type")))) %>%
summarise(across(all_of(variables_ecosystems[variable]),
list(mean = mean,
sd = sd)),
sample_size = n()) %>%
# To know of which variable the sample size is when you afterwards bind columns, add the name of the variable to the name of the sample size column.
rename_with( ~ paste0(variables_ecosystems[variable],
"_sample_size"),
matches("sample_size"))
}
# To have in the rows treatment and in the columns means, sd, and sample size, bind columns together.
ds_ecosystems_effect_size <- reduce(ds_ecosystems_effect_size,
full_join,
by = c("time_point",
"day",
"ecosystem_type",
"ecosystem_size_and_trophy",
"connection",
"ecosystem_size",
"ecosystem_size_ml",
"trophic_type",
"metaecosystem_type"))
## - Calculate Hedge's d. - ##
# Initialise the effect size columns
for (variable in length(variables_ecosystems)) {
ds_ecosystems_effect_size <- ds_ecosystems_effect_size %>%
mutate(!!paste0(variables_ecosystems[variable], "_d") := NA,
!!paste0(variables_ecosystems[variable], "_d_upper") := NA,
!!paste0(variables_ecosystems[variable], "_d_lower") := NA)
}
row_n = 0
# For each treatment at each time point, calculate effect size and 95% CI
for (treatment in 1:nrow(treatments_and_controls)) {
for (time_p in 1:length(time_points_for_ES)) {
row_n = row_n + 1
treatment_row = ds_ecosystems_effect_size %>%
filter(ecosystem_type == treatments_and_controls$treatment[treatment],
time_point == time_points_for_ES[time_p])
control_row = ds_ecosystems_effect_size %>%
filter(ecosystem_type == treatments_and_controls$control[treatment],
time_point == time_points_for_ES[time_p])
for (variable in 1:length(variables_ecosystems)) {
hedges_d = calculate.hedges_d(
treatment_row[[paste0(variables_ecosystems[variable], "_mean")]],
treatment_row[[paste0(variables_ecosystems[variable], "_sd")]],
treatment_row[[paste0(variables_ecosystems[variable], "_sample_size")]],
control_row[[paste0(variables_ecosystems[variable], "_mean")]],
control_row[[paste0(variables_ecosystems[variable], "_sd")]],
control_row[[paste0(variables_ecosystems[variable], "_sample_size")]])
ds_ecosystems_effect_size[[paste0(variables_ecosystems[variable], "_d")]][
ds_ecosystems_effect_size$ecosystem_type ==
treatments_and_controls$treatment[treatment] &
ds_ecosystems_effect_size$time_point ==
time_points_for_ES[time_p]] =
hedges_d$d
ds_ecosystems_effect_size[[paste0(variables_ecosystems[variable], "_d_upper")]][
ds_ecosystems_effect_size$ecosystem_type ==
treatments_and_controls$treatment[treatment] &
ds_ecosystems_effect_size$time_point ==
time_points_for_ES[time_p]] =
hedges_d$upper_CI
ds_ecosystems_effect_size[[paste0(variables_ecosystems[variable], "_d_lower")]][
ds_ecosystems_effect_size$ecosystem_type ==
treatments_and_controls$treatment[treatment] &
ds_ecosystems_effect_size$time_point ==
time_points_for_ES[time_p]] =
hedges_d$lower_CI
}
}
}
## - Retain only the connected ecosystems, discarding the controls (unconnected). - ##
ds_ecosystems_effect_size = ds_ecosystems_effect_size %>%
filter(connection == "connected")
However, Hedge’s d because of how much it depends on the pooled
spread of the treatment and control might be harder to interpret than
the log response ratio. Therefore, even though the log response ratio
might not be calculated for all the protist species, we also decide to
calculate it as well. To calculate the log response ratio of the
dominance of protist species I use here the package
SingleCaseES (see this
link). This package. The package provides the function
LRRi which calculates effect sizes for a single study case.
It also adjust for small sample sizes by default.
## - Calculate the effect size (Log Response Ratio). - ##
# Initialise the effect size columns
for (variable in length(protist_species_dominance)) {
ds_ecosystems_effect_size <- ds_ecosystems_effect_size %>%
mutate(!!paste0(protist_species_dominance[variable], "_LRR") := NA,
!!paste0(protist_species_dominance[variable], "_LRR_upper") := NA,
!!paste0(protist_species_dominance[variable], "_LRR_lower") := NA)
}
row_n = 0
# For each treatment, time point, and variable calculate LRR and 95% CI
for (treatment in 1:nrow(treatments_and_controls)) {
for (time_p in 1:length(time_points_for_ES)) {
for (variable in 1:length(protist_species_dominance)) {
row_n = row_n + 1
treatment_values = ds_ecosystems %>%
filter(ecosystem_type == treatments_and_controls$treatment[treatment],
time_point == time_points_for_ES[time_p],
!is.na(!!sym(protist_species_dominance[variable]))) %>%
pull(!!sym(protist_species_dominance[variable]))
control_values = ds_ecosystems %>%
filter(ecosystem_type == treatments_and_controls$control[treatment],
time_point == time_points_for_ES[time_p],
!is.na(!!sym(protist_species_dominance[variable]))) %>%
pull(!!sym(protist_species_dominance[variable]))
# By default it corrects for small sample sizes and calculates 95 % CI.
LRR_output = LRRi(A_data = control_values,
B_data = treatment_values,
scale = "proportion")
ds_ecosystems_effect_size[[paste0(protist_species_dominance[variable], "_LRR")]][
ds_ecosystems_effect_size$ecosystem_type ==
treatments_and_controls$treatment[treatment] &
ds_ecosystems_effect_size$time_point ==
time_points_for_ES[time_p]] =
LRR_output$Est
ds_ecosystems_effect_size[[paste0(protist_species_dominance[variable], "_LRR_upper")]][
ds_ecosystems_effect_size$ecosystem_type ==
treatments_and_controls$treatment[treatment] &
ds_ecosystems_effect_size$time_point ==
time_points_for_ES[time_p]] =
LRR_output$CI_upper
ds_ecosystems_effect_size[[paste0(protist_species_dominance[variable], "_LRR_lower")]][
ds_ecosystems_effect_size$ecosystem_type ==
treatments_and_controls$treatment[treatment] &
ds_ecosystems_effect_size$time_point ==
time_points_for_ES[time_p]] =
LRR_output$CI_lower
}
}
}
ds_species_effect_sizes_d)# To be able to plot dominance for multiple species, get the effect sizes, their upper boundary, and their lower boundary in a long format.
filtered_data = ds_ecosystems_effect_size %>%
ungroup() %>%
filter(connection == "connected",
trophic_type == "heterotrophic") %>%
filter(time_point > 1) %>%
# To have a cleaner dataset that is easier to look at, select only the columns of the time point, ecosystem type, and protist species dominance (w/ CI).
select(time_point,
ecosystem_type,
paste0(protist_species_dominance, "_d"),
paste0(protist_species_dominance, "_d_upper"),
paste0(protist_species_dominance, "_d_lower"))
ds_species_effect_sizes_d = filtered_data %>%
pivot_longer(cols = ends_with("dominance_d"),
names_to = "species",
values_to = "effect_size") %>%
select(time_point,
ecosystem_type,
species,
effect_size)
ds_species_effect_sizes_d_upper = filtered_data %>%
pivot_longer(cols = ends_with("dominance_d_upper"),
names_to = "species",
values_to = "upper_95_CI") %>%
select(upper_95_CI)
ds_species_effect_sizes_d_lower = filtered_data %>%
pivot_longer(cols = ends_with("dominance_d_lower"),
names_to = "species",
values_to = "lower_95_CI") %>%
select(lower_95_CI)
ds_species_effect_sizes_d = cbind(ds_species_effect_sizes_d, ds_species_effect_sizes_d_upper, ds_species_effect_sizes_d_lower) %>%
mutate(species = str_remove(species, "_bioarea_mm2_per_ml_dominance_d")) %>%
# To understand if there is an effect on size distribution, plot the effects of connection on dominance by disposing species smallest to largest.
mutate(species = factor(x = species,
levels = c("Tet", "Col", "Eup", "Pau", "Cep", "Lox", "Pca", "Spi_te", "Ble", "Spi")))
ds_species_effect_sizes_LRR)# To be able to plot dominance for multiple species, get the effect sizes, their upper boundary, and their lower boundary in a long format.
filtered_data = ds_ecosystems_effect_size %>%
ungroup() %>%
filter(connection == "connected",
trophic_type == "heterotrophic") %>%
filter(time_point > 1) %>%
# To have a cleaner dataset that is easier to look at, select only the columns of the time point, ecosystem type, and protist species dominance (w/ CI).
select(time_point,
ecosystem_type,
paste0(protist_species_dominance, "_LRR"),
paste0(protist_species_dominance, "_LRR_upper"),
paste0(protist_species_dominance, "_LRR_lower"))
ds_species_effect_sizes_LRR = filtered_data %>%
pivot_longer(cols = ends_with("dominance_LRR"),
names_to = "species",
values_to = "effect_size") %>%
select(time_point,
ecosystem_type,
species,
effect_size)
ds_species_effect_sizes_LRR_upper = filtered_data %>%
pivot_longer(cols = ends_with("dominance_LRR_upper"),
names_to = "species",
values_to = "upper_95_CI") %>%
select(upper_95_CI)
ds_species_effect_sizes_LRR_lower = filtered_data %>%
pivot_longer(cols = ends_with("dominance_LRR_lower"),
names_to = "species",
values_to = "lower_95_CI") %>%
select(lower_95_CI)
ds_species_effect_sizes_LRR = cbind(ds_species_effect_sizes_LRR, ds_species_effect_sizes_LRR_upper, ds_species_effect_sizes_LRR_lower) %>%
mutate(species = str_remove(species, "_bioarea_mm2_per_ml_dominance_LRR")) %>%
# To understand if there is an effect on size distribution, plot the effects of connection on dominance by disposing species smallest to largest.
mutate(species = factor(x = species,
levels = c("Tet", "Col", "Eup", "Pau", "Cep", "Lox", "Pca", "Spi_te", "Ble", "Spi")))
ds_metaecosystems)# --- IDENTIFY ECOSYSTEM COMBINATIONS THAT CONSTITUTE CONNECTED META-ECOSYSTEMS --- #
combinations_connected = ds_ecosystems %>%
filter(
# To have the information about to which system nr and metaecosystem type
# each ecosystem belongs, we select one of the time points to don't have
# multiple information of the same ecosystem.
time_point == 0,
# To create only combinations for connected metaecosystems,
# we filter the combinations of only connected ecosystems.
connection == "connected") %>%
select(system_nr,
ecosystem_ID,
metaecosystem_type,
connection,
metaeco_type_n_connection) %>%
# To know which ecosystems were combined to for the connected meta-ecosystem,
# assign the ecosystem ID to the first and second ecosystems as mean ± 0.5.
# This is because the two ecosystems of a meta-ecosystem are two integers
# next to each other (e.g., 31 and 32).
group_by(system_nr,
metaecosystem_type,
connection,
metaeco_type_n_connection) %>%
summarise(ID_first_ecosystem = (mean(ecosystem_ID) - 0.5),
ID_second_ecosystem = (mean(ecosystem_ID) + 0.5)) %>%
mutate(ecosystems_combined = paste0(ID_first_ecosystem,
"|",
ID_second_ecosystem)) %>%
as.data.frame()
# --- IDENTIFY THE COMBINATIONS OF ECOSYSTEMS THAT CONSTITUTE UNCONNECTED META-ECOSYSTEMS --- #
# Determine ecosystems IDs of unconnected autotrophic ecosystems
ID_unconnected_S_autotrophic = ds_ecosystems %>%
filter(ecosystem_type == "Small autotrophic unconnected") %>%
pull(ecosystem_ID) %>%
unique()
ID_unconnected_M_autotrophic = ds_ecosystems %>%
filter(ecosystem_type == "Medium autotrophic unconnected") %>%
pull(ecosystem_ID) %>%
unique()
ID_unconnected_L_autotrophic = ds_ecosystems %>%
filter(ecosystem_type == "Large autotrophic unconnected") %>%
pull(ecosystem_ID) %>%
unique()
# Determine ecosystems IDs of unconnected heterotrophic ecosystems
ID_unconnected_S_heterotrophic = ds_ecosystems %>%
filter(ecosystem_type == "Small heterotrophic unconnected") %>%
pull(ecosystem_ID) %>%
unique()
ID_unconnected_M_heterotrophic = ds_ecosystems %>%
filter(ecosystem_type == "Medium heterotrophic unconnected") %>%
pull(ecosystem_ID) %>%
unique()
ID_unconnected_L_heterotrophic = ds_ecosystems %>%
filter(ecosystem_type == "Large heterotrophic unconnected") %>%
pull(ecosystem_ID) %>%
unique()
# Find combinations
combinations_heterotrophic_dominated = crossing(ID_unconnected_L_heterotrophic,
ID_unconnected_S_autotrophic) %>%
mutate(metaecosystem_type = "HD",
connection = "unconnected") %>%
rename(ID_first_ecosystem = ID_unconnected_L_heterotrophic,
ID_second_ecosystem = ID_unconnected_S_autotrophic) %>%
select(metaecosystem_type,
connection,
ID_first_ecosystem,
ID_second_ecosystem)
combinations_equally_dominated = crossing(ID_unconnected_M_heterotrophic,
ID_unconnected_M_autotrophic) %>%
mutate(metaecosystem_type = "ED",
connection = "unconnected") %>%
rename(ID_first_ecosystem = ID_unconnected_M_heterotrophic,
ID_second_ecosystem = ID_unconnected_M_autotrophic) %>%
select(metaecosystem_type,
connection,
ID_first_ecosystem,
ID_second_ecosystem)
combinations_autotrophic_dominated = crossing(ID_unconnected_S_heterotrophic,
ID_unconnected_L_autotrophic) %>%
mutate(metaecosystem_type = "AD",
connection = "unconnected") %>%
rename(ID_first_ecosystem = ID_unconnected_S_heterotrophic,
ID_second_ecosystem = ID_unconnected_L_autotrophic) %>%
select(metaecosystem_type,
connection,
ID_first_ecosystem,
ID_second_ecosystem)
# Bind combinations
combinations_unconnected = rbind(combinations_autotrophic_dominated,
combinations_heterotrophic_dominated,
combinations_equally_dominated) %>%
# To have a system nr for all the unconnected meta-ecosystems, give them a
# nr that starts from 1000, so that they can be distinguished
# from the connected meta-ecosystems.
mutate(system_nr = 1001:(1000 + nrow(.)),
connection = "unconnected",
metaeco_type_n_connection = paste(metaecosystem_type, connection),
ecosystems_combined = paste0(ID_first_ecosystem, "|", ID_second_ecosystem)) %>%
select(system_nr,
metaecosystem_type,
connection,
metaeco_type_n_connection,
ID_first_ecosystem,
ID_second_ecosystem,
ecosystems_combined)
# --- BIND CONNECTED AND UNCONNECTED META-ECOSYSTEM COMBINATIONS --- #
ecosystem_combinations = rbind(combinations_connected,
combinations_unconnected)
# --- USE ECOSYSTEM COMBINATIONS TO CREATE DS_METAECOSYSTEMS --- #
# Set parameters
row_i = 0
# Create ds_metaecosystems
for (combination in 1 : nrow(ecosystem_combinations)) {
for (time_p in time_points) {
# Set parameters
row_i = row_i + 1
# Create ds_metaecosystems row
ds_metaecosystems[[row_i]] = ds_ecosystems %>%
filter(
ecosystem_ID %in% c(
ecosystem_combinations[combination, ]$ID_first_ecosystem,
ecosystem_combinations[combination, ]$ID_second_ecosystem),
time_point == time_p) %>%
# Calculate meta-ecosystem metrics
summarise(total_metaecosystem_bioarea_mm2 = sum(bioarea_tot_mm2)) %>%
mutate(time_point = time_p,
# To know on which day the meta-ecosystem was sampled, select the
# sampling day that is time_p + 1. This is because the first
# sampling day is at time point 0, so all the days are shifted of
# 1 on place (e.g., the sampling day of time point 1 is at
# sampling_days[2]).
day = sampling_days[time_p + 1],
system_nr = ecosystem_combinations[combination, ]$system_nr,
ecosystems_combined = ecosystem_combinations[combination, ]$ecosystems_combined,
metaecosystem_type = ecosystem_combinations[combination, ]$metaecosystem_type,
connection = ecosystem_combinations[combination, ]$connection,
metaeco_type_n_connection = paste(metaecosystem_type, connection)) %>%
ungroup()
}
}
# Finish up ds_metaecosystems
ds_metaecosystems = ds_metaecosystems %>%
bind_rows() %>%
as.data.frame() %>%
select(time_point,
day,
system_nr,
ecosystems_combined,
metaecosystem_type,
metaeco_type_n_connection,
connection,
total_metaecosystem_bioarea_mm2) %>%
filter(!system_nr %in% metaecosystems_to_take_off)
unconnected_combinations_sets &
sets_of_sets)In the previous section of code, we identified combinations of
ecosystems that form unconnected meta-ecosystems. However, directly
comparing all unconnected meta-ecosystems to connected ones would
inflate our degrees of freedom due to autocorrelation among unconnected
meta-ecosystems sharing the same ecosystem. To address this, we will
compare five connected meta-ecosystems to five unconnected
meta-ecosystems in the analysis, each comparison comprising different
combinations of unconnected meta-ecosystems. In each comparison, we
create a “combination set” of unconnected meta-ecosystems. For each
combination set (e.g., ED unconnected), we assign numerical order to the
first ecosystem type (e.g., medium heterotrophic) and permute the order
of the second type’s ecosystems (e.g., medium autotrophic). For example,
let’s sat we are trying to create combination sets of ED unconnected
where the first ecosystem type is medium heterotrophic (1,2,3,4,5), and
the second type is medium autotrophic (6,7,8,9,10). Combinations of the
first ecosystem type in numerical order (1,2,3,4,5; 1,2,3,4,5; etc.) and
permutations of the second ecosystem type (e.g., 6,7,8,9,10; 6,7,8,10,9;
etc.) would give us the following: 1|6, 1|7, 1|8, 1|9, 1|10; 1|6, 1|7,
1|8, 1|10, 1|9; etc. To create an object which combines HD, ED, and AD
unconnected meta-ecosystem sets (sets_of_sets) we need to
go through the following steps. (1) Create a function to combine
unconnected meta-ecosystems into sets where each ecosystem appears only
once. (2) Find the combination sets for HD, ED, and AD unconnected
meta-ecosystems. (3) Find the sets of sets in which you combine all
three HD, ED, and AD unconnected meta-ecosystems
(sets_of_sets).
# --- CREATE FUNCTION TO COMBINE UNCONNECTED META-ECOSYSTEMS --- #
create.unconnected.sets = function(metaeco_type_n_connection_selected,
ecosystem_type_1,
ecosystem_type_2) {
# Find ID of the two ecosystems
ID_ecosystem_type_1 = ds_ecosystems %>%
filter(ecosystem_type == ecosystem_type_1) %>%
pull(ecosystem_ID) %>%
unique()
ID_ecosystem_type_2 = ds_ecosystems %>%
filter(ecosystem_type == ecosystem_type_2) %>%
pull(ecosystem_ID) %>%
unique()
# Create dataset with sets of unconnected meta-ecosystems
two_ecosystem_unconnected_sets <- data.frame(
# Give information on meta-ecosystem
metaeco_type = gsub(" unconnected", "", metaeco_type_n_connection_selected),
connection = "unconnected",
metaeco_type_n_connection = metaeco_type_n_connection_selected,
# Repeat the IDs of the ecosystem type 1 for as many times as the
# permutations of ecosystem type 2
ID_first_ecosystem = rep(ID_ecosystem_type_1,
times = length(permn(ID_ecosystem_type_2))),
# Permute the IDs of the ecosystem type 2
ID_second_ecosystem = unlist(flatten(permn(ID_ecosystem_type_2))),
# To have each set of unconnected meta-ecosystems to have a number, repeat
# the IDs of the ecosystem type ... for the number of ecosystem IDs of the
# ecosystem type ... (WARNING: if you want to do this code for another
# dataset it has to be done differently if you are taking off some
# ecosystems).
set = rep(1 : length(permn(ID_ecosystem_type_2)),
each = length(ID_ecosystem_type_1))) %>%
# To don't have problematic ecosystems, take them off (in our ecosystems
# we don't have to take them off though).
filter(!ID_first_ecosystem %in% ecosystems_to_take_off,
!ID_second_ecosystem %in% ecosystems_to_take_off) %>%
# To include other information for each unconnected metaecosystem, join
# with ecosystem_combinations.
full_join(ecosystem_combinations %>%
filter(metaeco_type_n_connection ==
metaeco_type_n_connection_selected)) %>%
select(set,
system_nr,
metaeco_type,
connection,
metaeco_type_n_connection,
ID_first_ecosystem,
ID_second_ecosystem,
ecosystems_combined)
# Return object 'two_ecosystem_unconnected_sets'
return(two_ecosystem_unconnected_sets)
}
## - (2) Find the combination sets for HD, ED, and AD unconnected meta-ecosystems. - ##
unconnected_combinations_sets = rbind(
create.unconnected.sets("AD unconnected",
"Small heterotrophic unconnected",
"Large autotrophic unconnected"),
create.unconnected.sets("HD unconnected",
"Large heterotrophic unconnected",
"Small autotrophic unconnected"),
create.unconnected.sets("ED unconnected",
"Medium heterotrophic unconnected",
"Medium autotrophic unconnected"))
## - (3) Find the sets of sets in which you combine all three HD, ED, and AD unconnected meta-ecosystems (sets_of_sets). - ##
sets_of_sets = expand.grid(autotrophic_dominated_set_n = unconnected_combinations_sets %>%
filter(metaeco_type_n_connection == "AD unconnected") %>%
pull(set) %>%
unique(),
heterotrophic_dominated_set_n = unconnected_combinations_sets %>%
filter(metaeco_type_n_connection == "HD unconnected") %>%
pull(set) %>%
unique(),
equally_dominated_set_n = unconnected_combinations_sets %>%
filter(metaeco_type_n_connection == "ED unconnected") %>%
pull(set) %>%
unique())
# --- DEFINE RESPONSE VARIABLE --- #
response_variable_selected = "total_metaecosystem_bioarea_mm2"
In the experiment we studied two-patch meta-ecosystems in which we manipulated the relative size of their patches (AD, ED, and HD) and their connection (unconnected vs connected). Now, we want to know whether meta-ecosystem patch size (here called meta-ecosystem type) influenced the effects of connection on this response variable. Therefore, we start by looking at how this response variable changed across time for all meta-ecosystems through its mean ± 95 confidence interval.
# --- PLOT ORIGINAL DATA --- #
plot.metaecos.points(ds_metaecosystems,
response_variable_selected,
3)
Following the initial inspection, we proceed to analyse statistical differences among meta-ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that data was filtered in the right way.
# --- PREPARE DATA FOR ANALYSIS --- #
data_for_analysis = ds_metaecosystems %>%
filter(time_point %in% time_points_model,
!is.na(!!sym(response_variable_selected)))
# --- PLOT DATA FOR ANALYSIS --- #
plot.metaecos.points(data_for_analysis,
response_variable_selected,
3)
# --- DEFINE NR OF BOOTSTRAP ITERATIONS --- #
bootstrap_iterations = 10
Then, to examine how the interaction between meta-ecosystem type and
connectivity influenced the response variable, we develop a mixed effect
model (full_model) with lmerTest (Kuznetsova et al., 2017),
treating system nr and time as random effects
(Response variable ~ type * connection + (1 | system_nr) + (1 |
day), see this
link for how to code). In this model we don’t use a Restricted
Maximum Likelihood (REML) because, while REML is robust to missing data,
it may not perform well with very small sample sizes, especially when
the number of random effects is large relative to the number of
observations (ChatGPT). After having created the model, we show (i) the
significance of the predictor variables through the summary of the model
and (ii) the model residuals.
Significance is tested by comparing their slope against zero using a t-test which employs the Satterthwaite’s method to estimate the degrees of freedom for the two groups (fixed variable slope and zero). This method is conservative in order to prevent false positives (Li & Redden, 2015). An alternative method that could be used is the Kenward-Roger’s method, however, it is expected to perform similarly. Because the model utilises Satterthwaite’s method, it should entail a Welch t-test (according to information gleaned from this Wikipedia page), which does not assume equal variance in the two groups. There is no option in this package to alter the type of t-test.
In this model, disconnected meta-ecosystems are made of paired unconnected ecosystems, which are paired randomly. However, how to pair unconnected ecosystems can be done in multiple ways, as unconnected ecosystems did not interact and therefore any combination between ecosystems would be arbitrary. To make sure that the random combination we selected did not bias our results, we run 10 possible combinations of ecosystems constituting unconnected meta-ecosystems and compute their p-values, creating a p-value distribution and keeping as the final p-value the mean of such distributions. Because explaining the reshuffling of ecosystems into different unconnected meta-ecosystems in the paper would be complex, we opted to present results for a single combination of unconnected ecosystems. Here, we provide a summary of the mixed effect model to illustrate the random effects.
# --- COMPUTE STATS FOR ALL ECOSYSTEM COMBINATIONS --- #
# If you see "Warning in (function (iprint = 0L, maxfun = 10000L, FtolAbs = 1e-05, FtolRel = ## 1e-15, : unused control arguments ignored", Ignore it. It just means that you didn't pass the control argument to the Nelder_Mead optimiser, so it uses the default.
# Initialise lists
set_data_for_analysis = list()
coefficients = list()
full_model = list()
# Get the number of rows in the sets_of_sets data frame
n_sets_of_sets = nrow(sets_of_sets)
# Generate random sets of indices for bootstrap iterations
random_sets_of_sets <- runif(bootstrap_iterations,
min = 1,
max = n_sets_of_sets) %>% round()
# Set the optimizer inputs for model fitting
optimizer_input = "optimx"
method_input = "L-BFGS-B"
# Loop through each randomly selected set of sets
for (i in 1:length(random_sets_of_sets)) {
# Get the current set of sets based on the random index
sets = sets_of_sets[i,]
# Identify system numbers that are unconnected based on the metaecosystem type
unconnected_system_nrs = unconnected_combinations_sets %>%
filter((metaeco_type_n_connection == "AD unconnected" & set == sets$autotrophic_dominated_set_n) |
(metaeco_type_n_connection == "ED unconnected" & set == sets$equally_dominated_set_n) |
(metaeco_type_n_connection == "HD unconnected" & set == sets$heterotrophic_dominated_set_n)) %>%
pull(system_nr) # Extract system numbers from the filtered data
# Filter the data for analysis based on connection status and unconnected systems
set_data_for_analysis[[i]] = data_for_analysis %>%
filter(connection == "connected" | system_nr %in% unconnected_system_nrs)
# Fit a generalized linear mixed model with a Tweedie distribution
# This is a try. I changed the lmer model with a tweedie glmmtmb.
full_model[[i]] = glmmTMB::glmmTMB(get(response_variable_selected) ~
metaecosystem_type * connection + # Model fixed effects
(1 | system_nr) + # Random effect for system number
(1 | day), # Random effect for day
data = set_data_for_analysis[[i]], # Data for the current set
REML = FALSE, # Use maximum likelihood estimation
family = glmmTMB::tweedie(link = "log")) # Tweedie family with log link
# Optionally, you could fit a linear mixed-effects model instead (commented out)
# full_model[[i]] = lmer(
# get(response_variable_selected) ~
# metaecosystem_type * connection +
# (1 | system_nr) +
# (1 | day),
# data = set_data_for_analysis[[i]],
# REML = FALSE,
# control = lmerControl(optimizer = optimizer_input,
# optCtrl = list(method = method_input)))
# Extract and store the coefficients from the model summary
coefficients[[i]] = summary(full_model[[i]])[["coefficients"]]
# Optionally, fit a null model without fixed effects (commented out)
# null_model = lmer(
# get(response_variable_selected) ~
# (1 | system_nr) +
# (1 | day),
# data = set_data_for_analysis[[i]],
# REML = FALSE,
# control = lmerControl(optimizer = optimizer_input,
# optCtrl = list(method = method_input)))
}
# Save the results
save(bootstrap_iterations,
file = here("3_results",
"mixed_effect_models",
"bootstrap_iterations.RData"))
save(random_sets_of_sets,
file = here("3_results",
"mixed_effect_models",
"random_sets_of_sets.RData"))
save(coefficients,
file = here("3_results",
"mixed_effect_models",
"bootstrapped_coefficients_metaecosystem_biomass.RData"))
# --- LOAD RESULTS --- #
load(file = here("3_results",
"mixed_effect_models",
"bootstrap_iterations.RData"))
load(file = here("3_results",
"mixed_effect_models",
"random_sets_of_sets.RData"))
load(file = here("3_results",
"mixed_effect_models",
"bootstrapped_coefficients_metaecosystem_biomass.RData"))
# --- SHOW MODEL SUMMARY --- #
print(summary(full_model[[1]]), digits = 3)
## Family: tweedie ( log )
## Formula:
## get(response_variable_selected) ~ metaecosystem_type * connection +
## (1 | system_nr) + (1 | day)
## Data: set_data_for_analysis[[i]]
##
## AIC BIC logLik deviance df.resid
## 1025.6 1050.6 -502.8 1005.6 80
##
## Random effects:
##
## Conditional model:
## Groups Name Variance Std.Dev.
## system_nr (Intercept) 0.00183 0.0428
## day (Intercept) 0.04298 0.2073
## Number of obs: 90, groups: system_nr, 30; day, 3
##
## Dispersion parameter for tweedie family (): 2.22
##
## Conditional model:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 5.8214 0.1335 43.6 < 2e-16
## metaecosystem_typeED -0.2346 0.0871 -2.7 0.0071
## metaecosystem_typeHD -0.4897 0.0910 -5.4 7.3e-08
## connectionconnected 0.2163 0.0810 2.7 0.0076
## metaecosystem_typeED:connectionconnected -0.2398 0.1221 -2.0 0.0495
## metaecosystem_typeHD:connectionconnected -0.6068 0.1310 -4.6 3.6e-06
##
## (Intercept) ***
## metaecosystem_typeED **
## metaecosystem_typeHD ***
## connectionconnected **
## metaecosystem_typeED:connectionconnected *
## metaecosystem_typeHD:connectionconnected ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# --- SHOW MODEL RESIDUALS --- #
create.res.vs.fit.metaecos(full_model[[1]],
set_data_for_analysis[[i]])
qqnorm(resid(full_model[[1]]))
qqline(resid(full_model[[1]]))
However, this model’s output complicates understanding the fixed effects. To enhance clarity in demonstrating the statistical significance of fixed effects, we employ a type III ANOVA on the full model. This method accommodates unbalanced designs and yields the same results to type I ANOVA in balanced designs (Uni Goettingen). We utilise Satterthwaite’s method to estimate the degrees of freedom for the two groups. But just knowing whether or not there is an effect is not enough. If there is an effect, we want to know which levels were different. Therefore, we proceed to analyse the contrasts among levels, ensuring that the P values go through a Tukey adjustment to account for the multiple comparisons (see this link for contrast coding).
# --- SHOW MODEL ANOVA --- #
anova_output = car::Anova(full_model[[1]], type = "III")
anova_output
## Analysis of Deviance Table (Type III Wald chisquare tests)
##
## Response: get(response_variable_selected)
## Chisq Df Pr(>Chisq)
## (Intercept) 1901.8170 1 < 2.2e-16 ***
## metaecosystem_type 29.0721 2 4.865e-07 ***
## connection 7.1273 1 0.007592 **
## metaecosystem_type:connection 21.4550 2 2.193e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# --- GET MODEL CONSTRASTS --- #
emmeans_output = emmeans(full_model[[1]],
specs = pairwise ~ metaecosystem_type:connection,
adjust = "tukey",
bias.adj = TRUE,
lmer.df = "satterthwaite")
emmeans_output
## $emmeans
## metaecosystem_type connection emmean SE df asymp.LCL asymp.UCL
## AD unconnected 5.82 0.133 Inf 5.56 6.08
## ED unconnected 5.59 0.136 Inf 5.32 5.85
## HD unconnected 5.33 0.138 Inf 5.06 5.60
## AD connected 6.04 0.132 Inf 5.78 6.30
## ED connected 5.56 0.136 Inf 5.30 5.83
## HD connected 4.94 0.143 Inf 4.66 5.22
##
## Results are given on the log (not the response) scale.
## Confidence level used: 0.95
##
## $contrasts
## contrast estimate SE df z.ratio p.value
## AD unconnected - ED unconnected 0.2346 0.0871 Inf 2.693 0.0766
## AD unconnected - HD unconnected 0.4897 0.0910 Inf 5.384 <.0001
## AD unconnected - AD connected -0.2163 0.0810 Inf -2.670 0.0814
## AD unconnected - ED connected 0.2581 0.0866 Inf 2.979 0.0343
## AD unconnected - HD connected 0.8802 0.0975 Inf 9.028 <.0001
## ED unconnected - HD unconnected 0.2552 0.0933 Inf 2.736 0.0684
## ED unconnected - AD connected -0.4508 0.0840 Inf -5.368 <.0001
## ED unconnected - ED connected 0.0235 0.0904 Inf 0.260 0.9998
## ED unconnected - HD connected 0.6456 0.0995 Inf 6.490 <.0001
## HD unconnected - AD connected -0.7060 0.0881 Inf -8.011 <.0001
## HD unconnected - ED connected -0.2316 0.0939 Inf -2.466 0.1344
## HD unconnected - HD connected 0.3905 0.1031 Inf 3.789 0.0021
## AD connected - ED connected 0.4744 0.0845 Inf 5.612 <.0001
## AD connected - HD connected 1.0965 0.0948 Inf 11.572 <.0001
## ED connected - HD connected 0.6221 0.1004 Inf 6.194 <.0001
##
## Results are given on the log (not the response) scale.
## P value adjustment: tukey method for comparing a family of 6 estimates
# Give a name for each level which you want to compare
AD_unconnected = c(1, 0, 0, 0, 0, 0)
ED_unconnected = c(0, 1, 0, 0, 0, 0)
HD_unconnected = c(0, 0, 1, 0, 0, 0)
AD_connected = c(0, 0, 0, 1, 0, 0)
ED_connected = c(0, 0, 0, 0, 1, 0)
HD_connected = c(0, 0, 0, 0, 0, 1)
# Compute the contrasts
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("AD connection effect" = AD_connected - AD_unconnected,
"ED connection effect" = ED_connected - ED_unconnected,
"HD connection effect" = HD_connected - HD_unconnected,
"AD vs ED connected" = AD_connected - ED_connected,
"HD vs ED connected" = HD_connected - ED_connected,
"AD vs ED unconnected" = AD_unconnected - ED_unconnected,
"HD vs ED unconnected" = HD_unconnected - ED_unconnected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
z.ratio = round(z.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
# --- SHOW MODEL CONTRASTS --- #
contrasts
## contrast estimate SE df z.ratio p.value
## 1 AD connection effect 0.216 0.081 Inf 2.670 0.008 **
## 2 ED connection effect -0.024 0.090 Inf -0.260 0.795
## 3 HD connection effect -0.390 0.103 Inf -3.789 0.000 ***
## 4 AD vs ED connected 0.474 0.085 Inf 5.612 0.000 ***
## 5 HD vs ED connected -0.622 0.100 Inf -6.194 0.000 ***
## 6 AD vs ED unconnected 0.235 0.087 Inf 2.693 0.007 **
## 7 HD vs ED unconnected -0.255 0.093 Inf -2.736 0.006 **
To recap, we bootstrapped 10 random sets of unconnected meta-ecosystems which we compared to all the connected meta-ecosystems. We here show which sets were used, the results of ANOVA, and the results of the contrasts.
# --- SHOW WHICH RANDOM SETS OF SETS HAVE BOOTSTRAPPED --- #
# Show to make sure that there's no bias in which ecosystem combinations have
# been combined.
hist(random_sets_of_sets,
main = "Random sets of sets used for bootrapping")
# --- CALCULATE THE CONTRASTS FOR ALL ECOSYSTEM COMBINATIONS --- #
# Initialise lists
ANOVA_output = list()
emmeans_output = list()
contrasts = list()
# Loop through the sets of sets to calculate their contrasts
for (i in 1:length(random_sets_of_sets)){
# Perform ANOVA
ANOVA_output[[i]] = car::Anova(full_model[[i]]) %>%
as.data.frame() %>%
mutate(variable = rownames(.))
colnames(ANOVA_output[[i]]) = c("Chisq",
"Df",
"p",
"variable")
# Compute estimated marginal means (EMMeans) for the interaction of
# metaecosystem type and connection
emmeans_output[[i]] = emmeans(full_model[[i]],
specs = pairwise ~ metaecosystem_type:connection,
adjust = "tukey",
bias.adj = TRUE,
lmer.df = "satterthwaite")
AD_unconnected = c(1, 0, 0, 0, 0, 0)
ED_unconnected = c(0, 1, 0, 0, 0, 0)
HD_unconnected = c(0, 0, 1, 0, 0, 0)
AD_connected = c(0, 0, 0, 1, 0, 0)
ED_connected = c(0, 0, 0, 0, 1, 0)
HD_connected = c(0, 0, 0, 0, 0, 1)
contrasts[[i]] = contrast(emmeans_output[[i]],
method = list("AD connection effect" = AD_connected - AD_unconnected,
"ED connection effect" = ED_connected - ED_unconnected,
"HD connection effect" = HD_connected - HD_unconnected,
"AD vs ED connected" = AD_connected - ED_connected,
"HD vs ED connected" = ED_connected - HD_connected)) %>%
as.data.frame()
contrast_levels = contrasts[[i]]$contrast
}
# Average ANOVA across sets of sets
do.call(rbind, ANOVA_output) %>%
group_by(variable) %>%
summarise(Chisq = round(mean(Chisq), digits = 1),
Df = round(mean(Df), digits = 1),
p = round(mean(p), digits = 4)) %>%
mutate(variable = factor(variable,
levels = c("metaecosystem_type",
"connection",
"metaecosystem_type:connection"))) %>%
arrange(variable)
## # A tibble: 3 × 4
## variable Chisq Df p
## <fct> <dbl> <dbl> <dbl>
## 1 metaecosystem_type 140. 2 0
## 2 connection 0.1 1 0.708
## 3 metaecosystem_type:connection 21 2 0
# Average the contrasts across sets of sets
do.call(rbind, contrasts) %>%
group_by(contrast) %>%
summarise(estimate = round(mean(estimate), digits = 1),
SE = round(mean(SE), digits = 1),
df = round(mean(df), digits = 0),
z.ratio = round(mean(z.ratio), digits = 2),
p.value = round(mean(p.value), digits = 4)) %>%
mutate(contrast = factor(contrast,
levels = c("AD connection effect",
"ED connection effect",
"HD connection effect",
"AD vs ED connected",
"HD vs ED connected"))) %>%
arrange(contrast)
## # A tibble: 5 × 6
## contrast estimate SE df z.ratio p.value
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 AD connection effect 0.2 0.1 Inf 2.62 0.0088
## 2 ED connection effect 0 0.1 Inf -0.26 0.798
## 3 HD connection effect -0.4 0.1 Inf -3.76 0.0002
## 4 AD vs ED connected 0.5 0.1 Inf 5.53 0
## 5 HD vs ED connected 0.6 0.1 Inf 6.16 0
trophy_selected = "autotrophic"
response_variable = "bioarea_mm2_per_ml"
In our experiment, we manipulated meta-ecosystems consisting of autotrophic and heterotrophic patches, varying the relative size of these patches (referred to as meta-ecosystem types AD, ED, and HD) and their connectivity (unconnected versus connected). Now, we want to know whether, at the local ecosystem level, the connectivity of the ecosystem interacted with ecosystem size to affect this specific response variable. Essentially, we are interested in understanding if ecosystem size modulated the impact of spatial feedback locally. To begin, we plot how this response variable varied across different treatments throughout the experiment, represented by mean values with a 95% confidence interval.
plot.ecosystems.points(ds_ecosystems %>%
filter(trophic_type == trophy_selected),
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(ds_ecosystems,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
Following this initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.
filtered_data = ds_ecosystems %>%
filter(trophic_type == trophy_selected,
time_point %in% time_points_model,
!is.na(!!sym(response_variable))) %>%
mutate(ecosystem_ID = as.character(ecosystem_ID),
size = NA,
size = case_when(ecosystem_size == "Small" ~ "S",
ecosystem_size == "Medium" ~ "M",
ecosystem_size == "Large" ~ "L",
TRUE ~ size),
size = factor(size, levels = c("S", "M", "L")),
size = as.character(size))
plot.ecosystems.points(filtered_data,
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(filtered_data,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## - Create mixed effect model - ##
# In the ouput lmerModLmerTest which means that it's a Linear Mixed Model from the lmerTest package
if((response_variable %in% c("bioarea_mm2_per_ml", "indiv_per_ml", "median_body_size_µm2")) == FALSE){
model = lmer(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
REML = FALSE,
control = lmerControl(optimizer = "Nelder_Mead"))
}
## - Create mixed effect model - ##
model <- glmmTMB::glmmTMB(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
family = glmmTMB::tweedie(link = "log"))
## - Show summary of the model -- ##
print(summary(model), digits = 3)
## Family: tweedie ( log )
## Formula:
## get(response_variable) ~ size * connection + (1 | ecosystem_ID) +
## (1 | day)
## Data: filtered_data
##
## AIC BIC logLik deviance df.resid
## 422.6 447.6 -201.3 402.6 80
##
## Random effects:
##
## Conditional model:
## Groups Name Variance Std.Dev.
## ecosystem_ID (Intercept) 1.23e-10 1.11e-05
## day (Intercept) 1.04e-01 3.23e-01
## Number of obs: 90, groups: ecosystem_ID, 30; day, 3
##
## Dispersion parameter for tweedie family (): 0.556
##
## Conditional model:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 2.1055 0.2072 10.16 <2e-16 ***
## sizeM -0.0378 0.1277 -0.30 0.767
## sizeS -1.5262 0.1805 -8.46 <2e-16 ***
## connectionconnected 0.2617 0.1212 2.16 0.031 *
## sizeM:connectionconnected -0.3362 0.1782 -1.89 0.059 .
## sizeS:connectionconnected 0.2180 0.2357 0.92 0.355
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Plot residuals of the model -- ##
qqnorm(resid(model))
qqline(resid(model))
create.res.vs.fit.ecosystems(model,
filtered_data)
## - Perform Type III ANOVA on the model - ##
car::Anova(model, type = "III")
## Analysis of Deviance Table (Type III Wald chisquare tests)
##
## Response: get(response_variable)
## Chisq Df Pr(>Chisq)
## (Intercept) 103.2826 1 < 2e-16 ***
## size 79.8900 2 < 2e-16 ***
## connection 4.6614 1 0.03085 *
## size:connection 6.4376 2 0.04000 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Analyse the contrasts among levels -- ##
emmeans_output = emmeans(model,
specs = pairwise ~ size:connection,
adjust = "tukey",
bias.adj = TRUE,
lmer.df = "satterthwaite")
emmeans_output
## $emmeans
## size connection emmean SE df asymp.LCL asymp.UCL
## L unconnected 2.106 0.207 Inf 1.699 2.51
## M unconnected 2.068 0.208 Inf 1.660 2.48
## S unconnected 0.579 0.244 Inf 0.101 1.06
## L connected 2.367 0.204 Inf 1.968 2.77
## M connected 1.993 0.209 Inf 1.584 2.40
## S connected 1.059 0.229 Inf 0.611 1.51
##
## Results are given on the log (not the response) scale.
## Confidence level used: 0.95
##
## $contrasts
## contrast estimate SE df z.ratio p.value
## L unconnected - M unconnected 0.0378 0.128 Inf 0.296 0.9997
## L unconnected - S unconnected 1.5262 0.180 Inf 8.456 <.0001
## L unconnected - L connected -0.2617 0.121 Inf -2.159 0.2572
## L unconnected - M connected 0.1123 0.129 Inf 0.868 0.9541
## L unconnected - S connected 1.0466 0.159 Inf 6.575 <.0001
## M unconnected - S unconnected 1.4884 0.180 Inf 8.254 <.0001
## M unconnected - L connected -0.2994 0.122 Inf -2.451 0.1391
## M unconnected - M connected 0.0745 0.131 Inf 0.571 0.9929
## M unconnected - S connected 1.0088 0.159 Inf 6.334 <.0001
## S unconnected - L connected -1.7879 0.176 Inf -10.130 <.0001
## S unconnected - M connected -1.4139 0.183 Inf -7.725 <.0001
## S unconnected - S connected -0.4796 0.202 Inf -2.373 0.1658
## L connected - M connected 0.3740 0.124 Inf 3.015 0.0309
## L connected - S connected 1.3082 0.155 Inf 8.457 <.0001
## M connected - S connected 0.9343 0.162 Inf 5.771 <.0001
##
## Results are given on the log (not the response) scale.
## P value adjustment: tukey method for comparing a family of 6 estimates
L_unconnected = c(1, 0, 0, 0, 0, 0)
M_unconnected = c(0, 1, 0, 0, 0, 0)
S_unconnected = c(0, 0, 1, 0, 0, 0)
L_connected = c(0, 0, 0, 1, 0, 0)
M_connected = c(0, 0, 0, 0, 1, 0)
S_connected = c(0, 0, 0, 0, 0, 1)
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
t.ratio = round(t.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
z.ratio = round(z.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## contrast estimate SE df z.ratio p.value
## 1 Small connection effect 0.480 0.202 Inf 2.373 0.018 *
## 2 Medium connection effect -0.075 0.131 Inf -0.571 0.568
## 3 Large connection effect 0.262 0.121 Inf 2.159 0.031 *
## 4 Size effect in unconnected (L - S) 1.526 0.180 Inf 8.456 0.000 ***
## 5 Size effect in unconnected (M - S) 1.488 0.180 Inf 8.254 0.000 ***
## 6 Size effect in connected (L - S) 1.308 0.155 Inf 8.457 0.000 ***
## 7 Size effect in connected (M - S) 0.934 0.162 Inf 5.771 0.000 ***
response_variable = "median_body_size_µm2"
In our experiment, we manipulated meta-ecosystems consisting of autotrophic and heterotrophic patches, varying the relative size of these patches (referred to as meta-ecosystem types AD, ED, and HD) and their connectivity (unconnected versus connected). Now, we want to know whether, at the local ecosystem level, the connectivity of the ecosystem interacted with ecosystem size to affect this specific response variable. Essentially, we are interested in understanding if ecosystem size modulated the impact of spatial feedback locally. To begin, we plot how this response variable varied across different treatments throughout the experiment, represented by mean values with a 95% confidence interval.
plot.ecosystems.points(ds_ecosystems %>%
filter(trophic_type == trophy_selected),
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(ds_ecosystems,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
Following this initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.
filtered_data = ds_ecosystems %>%
filter(trophic_type == trophy_selected,
time_point %in% time_points_model,
!is.na(!!sym(response_variable))) %>%
mutate(ecosystem_ID = as.character(ecosystem_ID),
size = NA,
size = case_when(ecosystem_size == "Small" ~ "S",
ecosystem_size == "Medium" ~ "M",
ecosystem_size == "Large" ~ "L",
TRUE ~ size),
size = factor(size, levels = c("S", "M", "L")),
size = as.character(size))
plot.ecosystems.points(filtered_data,
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(filtered_data,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## - Create mixed effect model - ##
# In the ouput lmerModLmerTest which means that it's a Linear Mixed Model from the lmerTest package
if((response_variable %in% c("bioarea_mm2_per_ml", "indiv_per_ml", "median_body_size_µm2")) == FALSE){
model = lmer(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
REML = FALSE,
control = lmerControl(optimizer = "Nelder_Mead"))
}
## - Create mixed effect model - ##
model <- glmmTMB::glmmTMB(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
family = glmmTMB::tweedie(link = "log"))
## - Show summary of the model -- ##
print(summary(model), digits = 3)
## Family: tweedie ( log )
## Formula:
## get(response_variable) ~ size * connection + (1 | ecosystem_ID) +
## (1 | day)
## Data: filtered_data
##
## AIC BIC logLik deviance df.resid
## 1033.2 1058.2 -506.6 1013.2 80
##
## Random effects:
##
## Conditional model:
## Groups Name Variance Std.Dev.
## ecosystem_ID (Intercept) 0.00131 0.0361
## day (Intercept) 0.00707 0.0841
## Number of obs: 90, groups: ecosystem_ID, 30; day, 3
##
## Dispersion parameter for tweedie family (): 3.78
##
## Conditional model:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 6.8945 0.0536 128.6 <2e-16 ***
## sizeM -0.0096 0.0322 -0.3 0.7655
## sizeS -0.3018 0.0335 -9.0 <2e-16 ***
## connectionconnected 0.0335 0.0320 1.0 0.2952
## sizeM:connectionconnected -0.1050 0.0456 -2.3 0.0214 *
## sizeS:connectionconnected -0.1363 0.0477 -2.9 0.0042 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Plot residuals of the model -- ##
qqnorm(resid(model))
qqline(resid(model))
create.res.vs.fit.ecosystems(model,
filtered_data)
## - Perform Type III ANOVA on the model - ##
car::Anova(model, type = "III")
## Analysis of Deviance Table (Type III Wald chisquare tests)
##
## Response: get(response_variable)
## Chisq Df Pr(>Chisq)
## (Intercept) 16543.0476 1 < 2.2e-16 ***
## size 102.1084 2 < 2.2e-16 ***
## connection 1.0956 1 0.295223
## size:connection 9.3478 2 0.009336 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Analyse the contrasts among levels -- ##
emmeans_output = emmeans(model,
specs = pairwise ~ size:connection,
adjust = "tukey",
bias.adj = TRUE,
lmer.df = "satterthwaite")
emmeans_output
## $emmeans
## size connection emmean SE df asymp.LCL asymp.UCL
## L unconnected 6.89 0.0536 Inf 6.79 7.00
## M unconnected 6.88 0.0536 Inf 6.78 6.99
## S unconnected 6.59 0.0544 Inf 6.49 6.70
## L connected 6.93 0.0535 Inf 6.82 7.03
## M connected 6.81 0.0538 Inf 6.71 6.92
## S connected 6.49 0.0548 Inf 6.38 6.60
##
## Results are given on the log (not the response) scale.
## Confidence level used: 0.95
##
## $contrasts
## contrast estimate SE df z.ratio p.value
## L unconnected - M unconnected 0.0096 0.0322 Inf 0.298 0.9997
## L unconnected - S unconnected 0.3018 0.0335 Inf 9.009 <.0001
## L unconnected - L connected -0.0335 0.0320 Inf -1.047 0.9020
## L unconnected - M connected 0.0811 0.0325 Inf 2.497 0.1249
## L unconnected - S connected 0.4046 0.0341 Inf 11.883 <.0001
## M unconnected - S unconnected 0.2922 0.0335 Inf 8.713 <.0001
## M unconnected - L connected -0.0431 0.0320 Inf -1.345 0.7598
## M unconnected - M connected 0.0715 0.0325 Inf 2.199 0.2382
## M unconnected - S connected 0.3950 0.0341 Inf 11.589 <.0001
## S unconnected - L connected -0.3353 0.0334 Inf -10.047 <.0001
## S unconnected - M connected -0.2207 0.0338 Inf -6.527 <.0001
## S unconnected - S connected 0.1028 0.0353 Inf 2.910 0.0421
## L connected - M connected 0.1146 0.0323 Inf 3.543 0.0053
## L connected - S connected 0.4381 0.0339 Inf 12.914 <.0001
## M connected - S connected 0.3236 0.0344 Inf 9.416 <.0001
##
## Results are given on the log (not the response) scale.
## P value adjustment: tukey method for comparing a family of 6 estimates
L_unconnected = c(1, 0, 0, 0, 0, 0)
M_unconnected = c(0, 1, 0, 0, 0, 0)
S_unconnected = c(0, 0, 1, 0, 0, 0)
L_connected = c(0, 0, 0, 1, 0, 0)
M_connected = c(0, 0, 0, 0, 1, 0)
S_connected = c(0, 0, 0, 0, 0, 1)
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
t.ratio = round(t.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
z.ratio = round(z.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## contrast estimate SE df z.ratio p.value
## 1 Small connection effect -0.103 0.035 Inf -2.910 0.004 **
## 2 Medium connection effect -0.071 0.033 Inf -2.199 0.028 *
## 3 Large connection effect 0.033 0.032 Inf 1.047 0.295
## 4 Size effect in unconnected (L - S) 0.302 0.033 Inf 9.009 0.000 ***
## 5 Size effect in unconnected (M - S) 0.292 0.034 Inf 8.713 0.000 ***
## 6 Size effect in connected (L - S) 0.438 0.034 Inf 12.914 0.000 ***
## 7 Size effect in connected (M - S) 0.324 0.034 Inf 9.416 0.000 ***
ecosystem_type_i = c("Small heterotrophic unconnected",
"Medium heterotrophic unconnected",
"Large heterotrophic unconnected",
"Small heterotrophic connected",
"Medium heterotrophic connected",
"Large heterotrophic connected")
ecosystem_size_and_trophy_selected = c("Small heterotrophic",
"Medium heterotrophic",
"Large heterotrophic")
trophy_selected = "heterotrophic"
response_variable = "bioarea_mm2_per_ml"
In our experiment, we manipulated meta-ecosystems consisting of autotrophic and heterotrophic patches, varying the relative size of these patches (referred to as meta-ecosystem types AD, ED, and HD) and their connectivity (unconnected versus connected). Now, we want to know whether, at the local ecosystem level, the connectivity of the ecosystem interacted with ecosystem size to affect this specific response variable. Essentially, we are interested in understanding if ecosystem size modulated the impact of spatial feedback locally. To begin, we plot how this response variable varied across different treatments throughout the experiment, represented by mean values with a 95% confidence interval.
plot.ecosystems.points(ds_ecosystems %>%
filter(trophic_type == trophy_selected),
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(ds_ecosystems,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
Following this initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.
filtered_data = ds_ecosystems %>%
filter(trophic_type == trophy_selected,
time_point %in% time_points_model,
!is.na(!!sym(response_variable))) %>%
mutate(ecosystem_ID = as.character(ecosystem_ID),
size = NA,
size = case_when(ecosystem_size == "Small" ~ "S",
ecosystem_size == "Medium" ~ "M",
ecosystem_size == "Large" ~ "L",
TRUE ~ size),
size = factor(size, levels = c("S", "M", "L")),
size = as.character(size))
plot.ecosystems.points(filtered_data,
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(filtered_data,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## - Create mixed effect model - ##
# In the ouput lmerModLmerTest which means that it's a Linear Mixed Model from the lmerTest package
if((response_variable %in% c("bioarea_mm2_per_ml", "indiv_per_ml", "median_body_size_µm2")) == FALSE){
model = lmer(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
REML = FALSE,
control = lmerControl(optimizer = "Nelder_Mead"))
}
## - Create mixed effect model - ##
model <- glmmTMB::glmmTMB(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
family = glmmTMB::tweedie(link = "log"))
## - Show summary of the model -- ##
print(summary(model), digits = 3)
## Family: tweedie ( log )
## Formula:
## get(response_variable) ~ size * connection + (1 | ecosystem_ID) +
## (1 | day)
## Data: filtered_data
##
## AIC BIC logLik deviance df.resid
## 326.8 351.8 -153.4 306.8 80
##
## Random effects:
##
## Conditional model:
## Groups Name Variance Std.Dev.
## ecosystem_ID (Intercept) 0.00811 0.0901
## day (Intercept) 0.03772 0.1942
## Number of obs: 90, groups: ecosystem_ID, 30; day, 3
##
## Dispersion parameter for tweedie family (): 0.318
##
## Conditional model:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 1.636 0.151 10.85 < 2e-16 ***
## sizeM -0.309 0.146 -2.11 0.03469 *
## sizeS -0.500 0.150 -3.33 0.00087 ***
## connectionconnected -0.495 0.150 -3.29 0.00099 ***
## sizeM:connectionconnected 0.587 0.212 2.77 0.00566 **
## sizeS:connectionconnected -0.269 0.235 -1.15 0.25185
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Plot residuals of the model -- ##
qqnorm(resid(model))
qqline(resid(model))
create.res.vs.fit.ecosystems(model,
filtered_data)
## - Perform Type III ANOVA on the model - ##
car::Anova(model, type = "III")
## Analysis of Deviance Table (Type III Wald chisquare tests)
##
## Response: get(response_variable)
## Chisq Df Pr(>Chisq)
## (Intercept) 117.696 1 < 2.2e-16 ***
## size 11.553 2 0.0030994 **
## connection 10.840 1 0.0009935 ***
## size:connection 15.002 2 0.0005524 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Analyse the contrasts among levels -- ##
emmeans_output = emmeans(model,
specs = pairwise ~ size:connection,
adjust = "tukey",
bias.adj = TRUE,
lmer.df = "satterthwaite")
emmeans_output
## $emmeans
## size connection emmean SE df asymp.LCL asymp.UCL
## L unconnected 1.636 0.151 Inf 1.3400 1.931
## M unconnected 1.327 0.155 Inf 1.0223 1.632
## S unconnected 1.136 0.159 Inf 0.8233 1.448
## L connected 1.141 0.159 Inf 0.8300 1.452
## M connected 1.419 0.154 Inf 1.1177 1.720
## S connected 0.372 0.179 Inf 0.0207 0.724
##
## Results are given on the log (not the response) scale.
## Confidence level used: 0.95
##
## $contrasts
## contrast estimate SE df z.ratio p.value
## L unconnected - M unconnected 0.30855 0.146 Inf 2.112 0.2809
## L unconnected - S unconnected 0.49985 0.150 Inf 3.330 0.0112
## L unconnected - L connected 0.49463 0.150 Inf 3.292 0.0127
## L unconnected - M connected 0.21656 0.145 Inf 1.494 0.6680
## L unconnected - S connected 1.26322 0.174 Inf 7.277 <.0001
## M unconnected - S unconnected 0.19130 0.155 Inf 1.234 0.8204
## M unconnected - L connected 0.18608 0.155 Inf 1.199 0.8373
## M unconnected - M connected -0.09199 0.150 Inf -0.612 0.9902
## M unconnected - S connected 0.95467 0.178 Inf 5.365 <.0001
## S unconnected - L connected -0.00522 0.159 Inf -0.033 1.0000
## S unconnected - M connected -0.28329 0.155 Inf -1.833 0.4445
## S unconnected - S connected 0.76337 0.182 Inf 4.189 0.0004
## L connected - M connected -0.27807 0.153 Inf -1.813 0.4574
## L connected - S connected 0.76859 0.179 Inf 4.288 0.0003
## M connected - S connected 1.04666 0.174 Inf 6.021 <.0001
##
## Results are given on the log (not the response) scale.
## P value adjustment: tukey method for comparing a family of 6 estimates
L_unconnected = c(1, 0, 0, 0, 0, 0)
M_unconnected = c(0, 1, 0, 0, 0, 0)
S_unconnected = c(0, 0, 1, 0, 0, 0)
L_connected = c(0, 0, 0, 1, 0, 0)
M_connected = c(0, 0, 0, 0, 1, 0)
S_connected = c(0, 0, 0, 0, 0, 1)
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
t.ratio = round(t.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
z.ratio = round(z.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## contrast estimate SE df z.ratio p.value
## 1 Small connection effect -0.763 0.182 Inf -4.189 0.000 ***
## 2 Medium connection effect 0.092 0.150 Inf 0.612 0.540
## 3 Large connection effect -0.495 0.150 Inf -3.292 0.001 **
## 4 Size effect in unconnected (L - S) 0.500 0.150 Inf 3.330 0.001 **
## 5 Size effect in unconnected (M - S) 0.191 0.155 Inf 1.234 0.217
## 6 Size effect in connected (L - S) 0.769 0.179 Inf 4.288 0.000 ***
## 7 Size effect in connected (M - S) 1.047 0.174 Inf 6.021 0.000 ***
response_variable = "species_richness"
In our experiment, we manipulated meta-ecosystems consisting of autotrophic and heterotrophic patches, varying the relative size of these patches (referred to as meta-ecosystem types AD, ED, and HD) and their connectivity (unconnected versus connected). Now, we want to know whether, at the local ecosystem level, the connectivity of the ecosystem interacted with ecosystem size to affect this specific response variable. Essentially, we are interested in understanding if ecosystem size modulated the impact of spatial feedback locally. To begin, we plot how this response variable varied across different treatments throughout the experiment, represented by mean values with a 95% confidence interval.
plot.ecosystems.points(ds_ecosystems %>%
filter(trophic_type == trophy_selected),
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(ds_ecosystems,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
Following this initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.
filtered_data = ds_ecosystems %>%
filter(trophic_type == trophy_selected,
time_point %in% time_points_model,
!is.na(!!sym(response_variable))) %>%
mutate(ecosystem_ID = as.character(ecosystem_ID),
size = NA,
size = case_when(ecosystem_size == "Small" ~ "S",
ecosystem_size == "Medium" ~ "M",
ecosystem_size == "Large" ~ "L",
TRUE ~ size),
size = factor(size, levels = c("S", "M", "L")),
size = as.character(size))
plot.ecosystems.points(filtered_data,
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(filtered_data,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## - Create mixed effect model - ##
# In the ouput lmerModLmerTest which means that it's a Linear Mixed Model from the lmerTest package
if((response_variable %in% c("bioarea_mm2_per_ml", "indiv_per_ml", "median_body_size_µm2")) == FALSE){
model = lmer(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
REML = FALSE,
control = lmerControl(optimizer = "Nelder_Mead"))
}
## - Create mixed effect model - ##
model <- glmmTMB::glmmTMB(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
family = glmmTMB::tweedie(link = "log"))
## - Show summary of the model -- ##
print(summary(model), digits = 3)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
## method [lmerModLmerTest]
## Formula: get(response_variable) ~ size * connection + (1 | ecosystem_ID) +
## (1 | day)
## Data: filtered_data
## Control: lmerControl(optimizer = "Nelder_Mead")
##
## AIC BIC logLik deviance df.resid
## 313.4 335.9 -147.7 295.4 81
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.1410 -0.6293 -0.0135 0.5738 2.4523
##
## Random effects:
## Groups Name Variance Std.Dev.
## ecosystem_ID (Intercept) 0.000 0.000
## day (Intercept) 0.163 0.403
## Residual 1.486 1.219
## Number of obs: 90, groups: ecosystem_ID, 30; day, 3
##
## Fixed effects:
## Estimate Std. Error df t value Pr(>|t|)
## (Intercept) 6.733 0.392 13.467 17.20 1.5e-10 ***
## sizeM -0.600 0.445 87.000 -1.35 0.1812
## sizeS -1.467 0.445 87.000 -3.29 0.0014 **
## connectionconnected -0.600 0.445 87.000 -1.35 0.1812
## sizeM:connectionconnected 1.133 0.630 87.000 1.80 0.0753 .
## sizeS:connectionconnected -1.133 0.630 87.000 -1.80 0.0753 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) sizeM sizeS cnnctn szM:cn
## sizeM -0.569
## sizeS -0.569 0.500
## cnnctncnnct -0.569 0.500 0.500
## szM:cnnctnc 0.402 -0.707 -0.354 -0.707
## szS:cnnctnc 0.402 -0.354 -0.707 -0.707 0.500
## optimizer (Nelder_Mead) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
## - Plot residuals of the model -- ##
qqnorm(resid(model))
qqline(resid(model))
create.res.vs.fit.ecosystems(model,
filtered_data)
## - Perform Type III ANOVA on the model - ##
car::Anova(model, type = "III")
## Analysis of Deviance Table (Type III Wald chisquare tests)
##
## Response: get(response_variable)
## Chisq Df Pr(>Chisq)
## (Intercept) 295.7955 1 < 2.2e-16 ***
## size 10.9741 2 0.004140 **
## connection 1.8165 1 0.177725
## size:connection 12.9625 2 0.001532 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Analyse the contrasts among levels -- ##
emmeans_output = emmeans(model,
specs = pairwise ~ size:connection,
adjust = "tukey",
bias.adj = TRUE,
lmer.df = "satterthwaite")
emmeans_output
## $emmeans
## size connection emmean SE df lower.CL upper.CL
## L unconnected 6.73 0.392 13.5 5.89 7.58
## M unconnected 6.13 0.392 13.5 5.29 6.98
## S unconnected 5.27 0.392 13.5 4.42 6.11
## L connected 6.13 0.392 13.5 5.29 6.98
## M connected 6.67 0.392 13.5 5.82 7.51
## S connected 3.53 0.392 13.5 2.69 4.38
##
## Degrees-of-freedom method: satterthwaite
## Results are given on the get (not the response) scale.
## Confidence level used: 0.95
##
## $contrasts
## contrast estimate SE df t.ratio p.value
## L unconnected - M unconnected 0.6000 0.445 87 1.348 0.7575
## L unconnected - S unconnected 1.4667 0.445 87 3.295 0.0173
## L unconnected - L connected 0.6000 0.445 87 1.348 0.7575
## L unconnected - M connected 0.0667 0.445 87 0.150 1.0000
## L unconnected - S connected 3.2000 0.445 87 7.188 <.0001
## M unconnected - S unconnected 0.8667 0.445 87 1.947 0.3813
## M unconnected - L connected 0.0000 0.445 87 0.000 1.0000
## M unconnected - M connected -0.5333 0.445 87 -1.198 0.8367
## M unconnected - S connected 2.6000 0.445 87 5.840 <.0001
## S unconnected - L connected -0.8667 0.445 87 -1.947 0.3813
## S unconnected - M connected -1.4000 0.445 87 -3.145 0.0267
## S unconnected - S connected 1.7333 0.445 87 3.894 0.0026
## L connected - M connected -0.5333 0.445 87 -1.198 0.8367
## L connected - S connected 2.6000 0.445 87 5.840 <.0001
## M connected - S connected 3.1333 0.445 87 7.038 <.0001
##
## Note: contrasts are still on the get scale
## Degrees-of-freedom method: satterthwaite
## P value adjustment: tukey method for comparing a family of 6 estimates
L_unconnected = c(1, 0, 0, 0, 0, 0)
M_unconnected = c(0, 1, 0, 0, 0, 0)
S_unconnected = c(0, 0, 1, 0, 0, 0)
L_connected = c(0, 0, 0, 1, 0, 0)
M_connected = c(0, 0, 0, 0, 1, 0)
S_connected = c(0, 0, 0, 0, 0, 1)
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
t.ratio = round(t.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## contrast estimate SE df t.ratio p.value
## 1 Small connection effect -1.733 0.445 87 -3.894 0.000 ***
## 2 Medium connection effect 0.533 0.445 87 1.198 0.234
## 3 Large connection effect -0.600 0.445 87 -1.348 0.181
## 4 Size effect in unconnected (L - S) 1.467 0.445 87 3.295 0.001 **
## 5 Size effect in unconnected (M - S) 0.867 0.445 87 1.947 0.055
## 6 Size effect in connected (L - S) 2.600 0.445 87 5.840 0.000 ***
## 7 Size effect in connected (M - S) 3.133 0.445 87 7.038 0.000 ***
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
z.ratio = round(z.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
response_variable = "shannon"
In our experiment, we manipulated meta-ecosystems consisting of autotrophic and heterotrophic patches, varying the relative size of these patches (referred to as meta-ecosystem types AD, ED, and HD) and their connectivity (unconnected versus connected). Now, we want to know whether, at the local ecosystem level, the connectivity of the ecosystem interacted with ecosystem size to affect this specific response variable. Essentially, we are interested in understanding if ecosystem size modulated the impact of spatial feedback locally. To begin, we plot how this response variable varied across different treatments throughout the experiment, represented by mean values with a 95% confidence interval.
plot.ecosystems.points(ds_ecosystems %>%
filter(trophic_type == trophy_selected),
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(ds_ecosystems,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
Following this initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.
filtered_data = ds_ecosystems %>%
filter(trophic_type == trophy_selected,
time_point %in% time_points_model,
!is.na(!!sym(response_variable))) %>%
mutate(ecosystem_ID = as.character(ecosystem_ID),
size = NA,
size = case_when(ecosystem_size == "Small" ~ "S",
ecosystem_size == "Medium" ~ "M",
ecosystem_size == "Large" ~ "L",
TRUE ~ size),
size = factor(size, levels = c("S", "M", "L")),
size = as.character(size))
plot.ecosystems.points(filtered_data,
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(filtered_data,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## - Create mixed effect model - ##
# In the ouput lmerModLmerTest which means that it's a Linear Mixed Model from the lmerTest package
if((response_variable %in% c("bioarea_mm2_per_ml", "indiv_per_ml", "median_body_size_µm2")) == FALSE){
model = lmer(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
REML = FALSE,
control = lmerControl(optimizer = "Nelder_Mead"))
}
## - Create mixed effect model - ##
model <- glmmTMB::glmmTMB(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
family = glmmTMB::tweedie(link = "log"))
## - Show summary of the model -- ##
print(summary(model), digits = 3)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
## method [lmerModLmerTest]
## Formula: get(response_variable) ~ size * connection + (1 | ecosystem_ID) +
## (1 | day)
## Data: filtered_data
## Control: lmerControl(optimizer = "Nelder_Mead")
##
## AIC BIC logLik deviance df.resid
## 48.0 70.5 -15.0 30.0 81
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.839 -0.601 0.153 0.573 2.670
##
## Random effects:
## Groups Name Variance Std.Dev.
## ecosystem_ID (Intercept) 0.0000 0.000
## day (Intercept) 0.0000 0.000
## Residual 0.0817 0.286
## Number of obs: 90, groups: ecosystem_ID, 30; day, 3
##
## Fixed effects:
## Estimate Std. Error df t value Pr(>|t|)
## (Intercept) 1.2953 0.0738 90.0000 17.55 <2e-16 ***
## sizeM -0.0258 0.1044 90.0000 -0.25 0.806
## sizeS -0.2738 0.1044 90.0000 -2.62 0.010 *
## connectionconnected 0.0643 0.1044 90.0000 0.62 0.539
## sizeM:connectionconnected 0.1473 0.1476 90.0000 1.00 0.321
## sizeS:connectionconnected -0.2743 0.1476 90.0000 -1.86 0.066 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) sizeM sizeS cnnctn szM:cn
## sizeM -0.707
## sizeS -0.707 0.500
## cnnctncnnct -0.707 0.500 0.500
## szM:cnnctnc 0.500 -0.707 -0.354 -0.707
## szS:cnnctnc 0.500 -0.354 -0.707 -0.707 0.500
## optimizer (Nelder_Mead) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
## - Plot residuals of the model -- ##
qqnorm(resid(model))
qqline(resid(model))
create.res.vs.fit.ecosystems(model,
filtered_data)
## - Perform Type III ANOVA on the model - ##
car::Anova(model, type = "III")
## Analysis of Deviance Table (Type III Wald chisquare tests)
##
## Response: get(response_variable)
## Chisq Df Pr(>Chisq)
## (Intercept) 307.9480 1 < 2e-16 ***
## size 8.3894 2 0.01507 *
## connection 0.3799 1 0.53765
## size:connection 8.4010 2 0.01499 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Analyse the contrasts among levels -- ##
emmeans_output = emmeans(model,
specs = pairwise ~ size:connection,
adjust = "tukey",
bias.adj = TRUE,
lmer.df = "satterthwaite")
emmeans_output
## $emmeans
## size connection emmean SE df lower.CL upper.CL
## L unconnected 1.295 0.0738 90 1.149 1.442
## M unconnected 1.270 0.0738 90 1.123 1.416
## S unconnected 1.022 0.0738 90 0.875 1.168
## L connected 1.360 0.0738 90 1.213 1.506
## M connected 1.481 0.0738 90 1.335 1.628
## S connected 0.812 0.0738 90 0.665 0.958
##
## Degrees-of-freedom method: satterthwaite
## Results are given on the get (not the response) scale.
## Confidence level used: 0.95
##
## $contrasts
## contrast estimate SE df t.ratio p.value
## L unconnected - M unconnected 0.0258 0.104 90 0.247 0.9999
## L unconnected - S unconnected 0.2738 0.104 90 2.623 0.1023
## L unconnected - L connected -0.0643 0.104 90 -0.616 0.9896
## L unconnected - M connected -0.1859 0.104 90 -1.781 0.4833
## L unconnected - S connected 0.4837 0.104 90 4.634 0.0002
## M unconnected - S unconnected 0.2480 0.104 90 2.376 0.1759
## M unconnected - L connected -0.0901 0.104 90 -0.863 0.9542
## M unconnected - M connected -0.2117 0.104 90 -2.028 0.3352
## M unconnected - S connected 0.4579 0.104 90 4.387 0.0004
## S unconnected - L connected -0.3381 0.104 90 -3.239 0.0202
## S unconnected - M connected -0.4597 0.104 90 -4.403 0.0004
## S unconnected - S connected 0.2099 0.104 90 2.011 0.3444
## L connected - M connected -0.1215 0.104 90 -1.164 0.8524
## L connected - S connected 0.5480 0.104 90 5.250 <.0001
## M connected - S connected 0.6696 0.104 90 6.414 <.0001
##
## Note: contrasts are still on the get scale
## Degrees-of-freedom method: satterthwaite
## P value adjustment: tukey method for comparing a family of 6 estimates
L_unconnected = c(1, 0, 0, 0, 0, 0)
M_unconnected = c(0, 1, 0, 0, 0, 0)
S_unconnected = c(0, 0, 1, 0, 0, 0)
L_connected = c(0, 0, 0, 1, 0, 0)
M_connected = c(0, 0, 0, 0, 1, 0)
S_connected = c(0, 0, 0, 0, 0, 1)
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
t.ratio = round(t.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## contrast estimate SE df t.ratio p.value
## 1 Small connection effect -0.210 0.104 90 -2.011 0.047 *
## 2 Medium connection effect 0.212 0.104 90 2.028 0.046 *
## 3 Large connection effect 0.064 0.104 90 0.616 0.539
## 4 Size effect in unconnected (L - S) 0.274 0.104 90 2.623 0.010 *
## 5 Size effect in unconnected (M - S) 0.248 0.104 90 2.376 0.020 *
## 6 Size effect in connected (L - S) 0.548 0.104 90 5.250 0.000 ***
## 7 Size effect in connected (M - S) 0.670 0.104 90 6.414 0.000 ***
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
z.ratio = round(z.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
response_variable = "evenness_pielou"
In our experiment, we manipulated meta-ecosystems consisting of autotrophic and heterotrophic patches, varying the relative size of these patches (referred to as meta-ecosystem types AD, ED, and HD) and their connectivity (unconnected versus connected). Now, we want to know whether, at the local ecosystem level, the connectivity of the ecosystem interacted with ecosystem size to affect this specific response variable. Essentially, we are interested in understanding if ecosystem size modulated the impact of spatial feedback locally. To begin, we plot how this response variable varied across different treatments throughout the experiment, represented by mean values with a 95% confidence interval.
plot.ecosystems.points(ds_ecosystems %>%
filter(trophic_type == trophy_selected),
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(ds_ecosystems,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## Warning: Removed 50 rows containing non-finite outside the scale range
## (`stat_summary()`).
## Warning in max(f): no non-missing arguments to max; returning -Inf
## Warning: Computation failed in `stat_summary()`.
## Caused by error in `seq_len()`:
## ! argument must be coercible to non-negative integer
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## Warning: Removed 2 rows containing non-finite outside the scale range
## (`stat_summary()`).
## [1] Medium autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## Warning: Removed 50 rows containing non-finite outside the scale range
## (`stat_summary()`).
## Warning in max(f): no non-missing arguments to max; returning -Inf
## Warning: Computation failed in `stat_summary()`.
## Caused by error in `seq_len()`:
## ! argument must be coercible to non-negative integer
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## Warning: Removed 50 rows containing non-finite outside the scale range
## (`stat_summary()`).
## Warning in max(f): no non-missing arguments to max; returning -Inf
## Warning: Computation failed in `stat_summary()`.
## Caused by error in `seq_len()`:
## ! argument must be coercible to non-negative integer
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
Following this initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.
filtered_data = ds_ecosystems %>%
filter(trophic_type == trophy_selected,
time_point %in% time_points_model,
!is.na(!!sym(response_variable))) %>%
mutate(ecosystem_ID = as.character(ecosystem_ID),
size = NA,
size = case_when(ecosystem_size == "Small" ~ "S",
ecosystem_size == "Medium" ~ "M",
ecosystem_size == "Large" ~ "L",
TRUE ~ size),
size = factor(size, levels = c("S", "M", "L")),
size = as.character(size))
plot.ecosystems.points(filtered_data,
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(filtered_data,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## - Create mixed effect model - ##
# In the ouput lmerModLmerTest which means that it's a Linear Mixed Model from the lmerTest package
if((response_variable %in% c("bioarea_mm2_per_ml", "indiv_per_ml", "median_body_size_µm2")) == FALSE){
model = lmer(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
REML = FALSE,
control = lmerControl(optimizer = "Nelder_Mead"))
}
## - Create mixed effect model - ##
model <- glmmTMB::glmmTMB(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
family = glmmTMB::tweedie(link = "log"))
## - Show summary of the model -- ##
print(summary(model), digits = 3)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
## method [lmerModLmerTest]
## Formula: get(response_variable) ~ size * connection + (1 | ecosystem_ID) +
## (1 | day)
## Data: filtered_data
## Control: lmerControl(optimizer = "Nelder_Mead")
##
## AIC BIC logLik deviance df.resid
## -70.5 -48.2 44.3 -88.5 79
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -4.550 -0.476 0.093 0.661 1.790
##
## Random effects:
## Groups Name Variance Std.Dev.
## ecosystem_ID (Intercept) 0.0000 0.000
## day (Intercept) 0.0000 0.000
## Residual 0.0214 0.146
## Number of obs: 88, groups: ecosystem_ID, 30; day, 3
##
## Fixed effects:
## Estimate Std. Error df t value Pr(>|t|)
## (Intercept) 0.6881 0.0378 88.0000 18.21 <2e-16 ***
## sizeM 0.0233 0.0534 88.0000 0.44 0.66
## sizeS -0.0576 0.0534 88.0000 -1.08 0.28
## connectionconnected 0.0671 0.0534 88.0000 1.26 0.21
## sizeM:connectionconnected 0.0140 0.0756 88.0000 0.18 0.85
## sizeS:connectionconnected 0.0393 0.0770 88.0000 0.51 0.61
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) sizeM sizeS cnnctn szM:cn
## sizeM -0.707
## sizeS -0.707 0.500
## cnnctncnnct -0.707 0.500 0.500
## szM:cnnctnc 0.500 -0.707 -0.354 -0.707
## szS:cnnctnc 0.491 -0.347 -0.694 -0.694 0.491
## optimizer (Nelder_Mead) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
## - Plot residuals of the model -- ##
qqnorm(resid(model))
qqline(resid(model))
create.res.vs.fit.ecosystems(model,
filtered_data)
## - Perform Type III ANOVA on the model - ##
car::Anova(model, type = "III")
## Analysis of Deviance Table (Type III Wald chisquare tests)
##
## Response: get(response_variable)
## Chisq Df Pr(>Chisq)
## (Intercept) 331.6190 1 <2e-16 ***
## size 2.4267 2 0.2972
## connection 1.5775 1 0.2091
## size:connection 0.2661 2 0.8754
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Analyse the contrasts among levels -- ##
emmeans_output = emmeans(model,
specs = pairwise ~ size:connection,
adjust = "tukey",
bias.adj = TRUE,
lmer.df = "satterthwaite")
emmeans_output
## $emmeans
## size connection emmean SE df lower.CL upper.CL
## L unconnected 0.688 0.0378 88 0.613 0.763
## M unconnected 0.711 0.0378 88 0.636 0.786
## S unconnected 0.630 0.0378 88 0.555 0.706
## L connected 0.755 0.0378 88 0.680 0.830
## M connected 0.792 0.0378 88 0.717 0.867
## S connected 0.737 0.0406 88 0.656 0.818
##
## Degrees-of-freedom method: satterthwaite
## Results are given on the get (not the response) scale.
## Confidence level used: 0.95
##
## $contrasts
## contrast estimate SE df t.ratio p.value
## L unconnected - M unconnected -0.0233 0.0534 88 -0.435 0.9980
## L unconnected - S unconnected 0.0576 0.0534 88 1.078 0.8890
## L unconnected - L connected -0.0671 0.0534 88 -1.256 0.8077
## L unconnected - M connected -0.1043 0.0534 88 -1.953 0.3779
## L unconnected - S connected -0.0488 0.0555 88 -0.881 0.9502
## M unconnected - S unconnected 0.0808 0.0534 88 1.513 0.6569
## M unconnected - L connected -0.0439 0.0534 88 -0.821 0.9630
## M unconnected - M connected -0.0811 0.0534 88 -1.517 0.6542
## M unconnected - S connected -0.0256 0.0555 88 -0.461 0.9973
## S unconnected - L connected -0.1247 0.0534 88 -2.334 0.1919
## S unconnected - M connected -0.1619 0.0534 88 -3.030 0.0366
## S unconnected - S connected -0.1064 0.0555 88 -1.919 0.3977
## L connected - M connected -0.0372 0.0534 88 -0.697 0.9819
## L connected - S connected 0.0183 0.0555 88 0.330 0.9995
## M connected - S connected 0.0555 0.0555 88 1.001 0.9164
##
## Note: contrasts are still on the get scale
## Degrees-of-freedom method: satterthwaite
## P value adjustment: tukey method for comparing a family of 6 estimates
L_unconnected = c(1, 0, 0, 0, 0, 0)
M_unconnected = c(0, 1, 0, 0, 0, 0)
S_unconnected = c(0, 0, 1, 0, 0, 0)
L_connected = c(0, 0, 0, 1, 0, 0)
M_connected = c(0, 0, 0, 0, 1, 0)
S_connected = c(0, 0, 0, 0, 0, 1)
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
t.ratio = round(t.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## contrast estimate SE df t.ratio p.value
## 1 Small connection effect 0.106 0.055 88 1.919 0.058
## 2 Medium connection effect 0.081 0.053 88 1.517 0.133
## 3 Large connection effect 0.067 0.053 88 1.256 0.212
## 4 Size effect in unconnected (L - S) 0.058 0.053 88 1.078 0.284
## 5 Size effect in unconnected (M - S) 0.081 0.053 88 1.513 0.134
## 6 Size effect in connected (L - S) 0.018 0.055 88 0.330 0.742
## 7 Size effect in connected (M - S) 0.056 0.055 88 1.001 0.320
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
z.ratio = round(z.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
response_variable = "median_body_size_µm2"
In our experiment, we manipulated meta-ecosystems consisting of autotrophic and heterotrophic patches, varying the relative size of these patches (referred to as meta-ecosystem types AD, ED, and HD) and their connectivity (unconnected versus connected). Now, we want to know whether, at the local ecosystem level, the connectivity of the ecosystem interacted with ecosystem size to affect this specific response variable. Essentially, we are interested in understanding if ecosystem size modulated the impact of spatial feedback locally. To begin, we plot how this response variable varied across different treatments throughout the experiment, represented by mean values with a 95% confidence interval.
plot.ecosystems.points(ds_ecosystems %>%
filter(trophic_type == trophy_selected),
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(ds_ecosystems,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
Following this initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.
filtered_data = ds_ecosystems %>%
filter(trophic_type == trophy_selected,
time_point %in% time_points_model,
!is.na(!!sym(response_variable))) %>%
mutate(ecosystem_ID = as.character(ecosystem_ID),
size = NA,
size = case_when(ecosystem_size == "Small" ~ "S",
ecosystem_size == "Medium" ~ "M",
ecosystem_size == "Large" ~ "L",
TRUE ~ size),
size = factor(size, levels = c("S", "M", "L")),
size = as.character(size))
plot.ecosystems.points(filtered_data,
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(filtered_data,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## - Create mixed effect model - ##
# In the ouput lmerModLmerTest which means that it's a Linear Mixed Model from the lmerTest package
if((response_variable %in% c("bioarea_mm2_per_ml", "indiv_per_ml", "median_body_size_µm2")) == FALSE){
model = lmer(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
REML = FALSE,
control = lmerControl(optimizer = "Nelder_Mead"))
}
## - Create mixed effect model - ##
model <- glmmTMB::glmmTMB(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
family = glmmTMB::tweedie(link = "log"))
## Warning in finalizeTMB(TMBStruc, obj, fit, h, data.tmb.old): Model convergence
## problem; false convergence (8). See vignette('troubleshooting'),
## help('diagnose')
## - Show summary of the model -- ##
print(summary(model), digits = 3)
## Family: tweedie ( log )
## Formula:
## get(response_variable) ~ size * connection + (1 | ecosystem_ID) +
## (1 | day)
## Data: filtered_data
##
## AIC BIC logLik deviance df.resid
## 1536.9 1561.9 -758.4 1516.9 80
##
## Random effects:
##
## Conditional model:
## Groups Name Variance Std.Dev.
## ecosystem_ID (Intercept) 1.02e-09 0.000032
## day (Intercept) 1.72e-02 0.131055
## Number of obs: 90, groups: ecosystem_ID, 30; day, 3
##
## Dispersion parameter for tweedie family (): 0.052
##
## Conditional model:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 8.4591 0.0959 88.2 <2e-16 ***
## sizeM -0.1325 0.0833 -1.6 0.112
## sizeS -0.0162 0.0833 -0.2 0.846
## connectionconnected -0.0062 0.0833 -0.1 0.941
## sizeM:connectionconnected 0.2771 0.1179 2.4 0.019 *
## sizeS:connectionconnected 0.0680 0.1179 0.6 0.564
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Plot residuals of the model -- ##
qqnorm(resid(model))
qqline(resid(model))
create.res.vs.fit.ecosystems(model,
filtered_data)
## - Perform Type III ANOVA on the model - ##
car::Anova(model, type = "III")
## Analysis of Deviance Table (Type III Wald chisquare tests)
##
## Response: get(response_variable)
## Chisq Df Pr(>Chisq)
## (Intercept) 7783.0609 1 < 2e-16 ***
## size 3.0132 2 0.22167
## connection 0.0055 1 0.94065
## size:connection 6.0031 2 0.04971 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Analyse the contrasts among levels -- ##
emmeans_output = emmeans(model,
specs = pairwise ~ size:connection,
adjust = "tukey",
bias.adj = TRUE,
lmer.df = "satterthwaite")
emmeans_output
## $emmeans
## size connection emmean SE df asymp.LCL asymp.UCL
## L unconnected 8.46 0.0959 Inf 8.27 8.65
## M unconnected 8.33 0.0959 Inf 8.14 8.51
## S unconnected 8.44 0.0959 Inf 8.25 8.63
## L connected 8.45 0.0959 Inf 8.26 8.64
## M connected 8.60 0.0960 Inf 8.41 8.79
## S connected 8.50 0.0959 Inf 8.32 8.69
##
## Results are given on the log (not the response) scale.
## Confidence level used: 0.95
##
## $contrasts
## contrast estimate SE df z.ratio p.value
## L unconnected - M unconnected 0.13251 0.0833 Inf 1.591 0.6047
## L unconnected - S unconnected 0.01619 0.0833 Inf 0.194 1.0000
## L unconnected - L connected 0.00620 0.0833 Inf 0.074 1.0000
## L unconnected - M connected -0.13837 0.0833 Inf -1.661 0.5580
## L unconnected - S connected -0.04557 0.0834 Inf -0.547 0.9942
## M unconnected - S unconnected -0.11632 0.0833 Inf -1.397 0.7292
## M unconnected - L connected -0.12631 0.0833 Inf -1.516 0.6542
## M unconnected - M connected -0.27088 0.0834 Inf -3.248 0.0148
## M unconnected - S connected -0.17808 0.0834 Inf -2.136 0.2684
## S unconnected - L connected -0.00999 0.0834 Inf -0.120 1.0000
## S unconnected - M connected -0.15456 0.0835 Inf -1.852 0.4323
## S unconnected - S connected -0.06177 0.0833 Inf -0.741 0.9767
## L connected - M connected -0.14457 0.0833 Inf -1.735 0.5087
## L connected - S connected -0.05178 0.0835 Inf -0.620 0.9896
## M connected - S connected 0.09280 0.0835 Inf 1.111 0.8769
##
## Results are given on the log (not the response) scale.
## P value adjustment: tukey method for comparing a family of 6 estimates
L_unconnected = c(1, 0, 0, 0, 0, 0)
M_unconnected = c(0, 1, 0, 0, 0, 0)
S_unconnected = c(0, 0, 1, 0, 0, 0)
L_connected = c(0, 0, 0, 1, 0, 0)
M_connected = c(0, 0, 0, 0, 1, 0)
S_connected = c(0, 0, 0, 0, 0, 1)
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
t.ratio = round(t.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
z.ratio = round(z.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## contrast estimate SE df z.ratio p.value
## 1 Small connection effect 0.062 0.083 Inf 0.741 0.458
## 2 Medium connection effect 0.271 0.083 Inf 3.248 0.001 **
## 3 Large connection effect -0.006 0.083 Inf -0.074 0.941
## 4 Size effect in unconnected (L - S) 0.016 0.083 Inf 0.194 0.846
## 5 Size effect in unconnected (M - S) -0.116 0.083 Inf -1.397 0.163
## 6 Size effect in connected (L - S) -0.052 0.084 Inf -0.620 0.535
## 7 Size effect in connected (M - S) 0.093 0.083 Inf 1.111 0.266
response_variable = "indiv_per_ml"
In our experiment, we manipulated meta-ecosystems consisting of autotrophic and heterotrophic patches, varying the relative size of these patches (referred to as meta-ecosystem types AD, ED, and HD) and their connectivity (unconnected versus connected). Now, we want to know whether, at the local ecosystem level, the connectivity of the ecosystem interacted with ecosystem size to affect this specific response variable. Essentially, we are interested in understanding if ecosystem size modulated the impact of spatial feedback locally. To begin, we plot how this response variable varied across different treatments throughout the experiment, represented by mean values with a 95% confidence interval.
plot.ecosystems.points(ds_ecosystems %>%
filter(trophic_type == trophy_selected),
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(ds_ecosystems,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large autotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
Following this initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.
filtered_data = ds_ecosystems %>%
filter(trophic_type == trophy_selected,
time_point %in% time_points_model,
!is.na(!!sym(response_variable))) %>%
mutate(ecosystem_ID = as.character(ecosystem_ID),
size = NA,
size = case_when(ecosystem_size == "Small" ~ "S",
ecosystem_size == "Medium" ~ "M",
ecosystem_size == "Large" ~ "L",
TRUE ~ size),
size = factor(size, levels = c("S", "M", "L")),
size = as.character(size))
plot.ecosystems.points(filtered_data,
response_variable,
legend_row_n_input = 3)
plot.ecosystems.replicates.one.by.one(filtered_data,
ecosystem_size_and_trophy_selected,
response_variable)
## [1] Small heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Medium heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## [1] Large heterotrophic
## 6 Levels: Small autotrophic Medium autotrophic ... Large heterotrophic
## - Create mixed effect model - ##
# In the ouput lmerModLmerTest which means that it's a Linear Mixed Model from the lmerTest package
if((response_variable %in% c("bioarea_mm2_per_ml", "indiv_per_ml", "median_body_size_µm2")) == FALSE){
model = lmer(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
REML = FALSE,
control = lmerControl(optimizer = "Nelder_Mead"))
}
## - Create mixed effect model - ##
model <- glmmTMB::glmmTMB(get(response_variable) ~
size * connection +
(1 | ecosystem_ID) +
(1 | day),
data = filtered_data,
family = glmmTMB::tweedie(link = "log"))
## - Show summary of the model -- ##
print(summary(model), digits = 3)
## Family: tweedie ( log )
## Formula:
## get(response_variable) ~ size * connection + (1 | ecosystem_ID) +
## (1 | day)
## Data: filtered_data
##
## AIC BIC logLik deviance df.resid
## 680.7 705.7 -330.3 660.7 80
##
## Random effects:
##
## Conditional model:
## Groups Name Variance Std.Dev.
## ecosystem_ID (Intercept) 0.0223 0.149
## day (Intercept) 0.0119 0.109
## Number of obs: 90, groups: ecosystem_ID, 30; day, 3
##
## Dispersion parameter for tweedie family (): 2.39
##
## Conditional model:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 3.683 0.116 31.9 < 2e-16 ***
## sizeM -0.268 0.141 -1.9 0.05722 .
## sizeS -0.481 0.146 -3.3 0.00098 ***
## connectionconnected -0.553 0.148 -3.7 0.00018 ***
## sizeM:connectionconnected 0.486 0.208 2.3 0.01976 *
## sizeS:connectionconnected -0.279 0.234 -1.2 0.23272
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Plot residuals of the model -- ##
qqnorm(resid(model))
qqline(resid(model))
create.res.vs.fit.ecosystems(model,
filtered_data)
## - Perform Type III ANOVA on the model - ##
car::Anova(model, type = "III")
## Analysis of Deviance Table (Type III Wald chisquare tests)
##
## Response: get(response_variable)
## Chisq Df Pr(>Chisq)
## (Intercept) 1015.025 1 < 2.2e-16 ***
## size 11.084 2 0.0039188 **
## connection 14.043 1 0.0001787 ***
## size:connection 11.670 2 0.0029240 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## - Analyse the contrasts among levels -- ##
emmeans_output = emmeans(model,
specs = pairwise ~ size:connection,
adjust = "tukey",
bias.adj = TRUE,
lmer.df = "satterthwaite")
emmeans_output
## $emmeans
## size connection emmean SE df asymp.LCL asymp.UCL
## L unconnected 3.68 0.116 Inf 3.46 3.91
## M unconnected 3.41 0.121 Inf 3.18 3.65
## S unconnected 3.20 0.127 Inf 2.95 3.45
## L connected 3.13 0.129 Inf 2.88 3.38
## M connected 3.35 0.123 Inf 3.11 3.59
## S connected 2.37 0.158 Inf 2.06 2.68
##
## Results are given on the log (not the response) scale.
## Confidence level used: 0.95
##
## $contrasts
## contrast estimate SE df z.ratio p.value
## L unconnected - M unconnected 0.2680 0.141 Inf 1.902 0.4011
## L unconnected - S unconnected 0.4805 0.146 Inf 3.296 0.0126
## L unconnected - L connected 0.5535 0.148 Inf 3.747 0.0025
## L unconnected - M connected 0.3356 0.142 Inf 2.357 0.1715
## L unconnected - S connected 1.3134 0.174 Inf 7.535 <.0001
## M unconnected - S unconnected 0.2125 0.150 Inf 1.414 0.7186
## M unconnected - L connected 0.2855 0.152 Inf 1.877 0.4166
## M unconnected - M connected 0.0677 0.147 Inf 0.460 0.9974
## M unconnected - S connected 1.0454 0.178 Inf 5.871 <.0001
## S unconnected - L connected 0.0730 0.157 Inf 0.466 0.9973
## S unconnected - M connected -0.1449 0.152 Inf -0.955 0.9318
## S unconnected - S connected 0.8328 0.182 Inf 4.581 0.0001
## L connected - M connected -0.2178 0.153 Inf -1.419 0.7152
## L connected - S connected 0.7599 0.183 Inf 4.147 0.0005
## M connected - S connected 0.9777 0.179 Inf 5.458 <.0001
##
## Results are given on the log (not the response) scale.
## P value adjustment: tukey method for comparing a family of 6 estimates
L_unconnected = c(1, 0, 0, 0, 0, 0)
M_unconnected = c(0, 1, 0, 0, 0, 0)
S_unconnected = c(0, 0, 1, 0, 0, 0)
L_connected = c(0, 0, 0, 1, 0, 0)
M_connected = c(0, 0, 0, 0, 1, 0)
S_connected = c(0, 0, 0, 0, 0, 1)
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
t.ratio = round(t.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## - Show only the contrasts you are interested in -- ##
n_of_digits = 3
contrasts = contrast(emmeans_output,
method = list("Small connection effect" = S_connected - S_unconnected,
"Medium connection effect" = M_connected - M_unconnected,
"Large connection effect" = L_connected - L_unconnected,
"Size effect in unconnected (L - S)" = L_unconnected - S_unconnected,
"Size effect in unconnected (M - S)" = M_unconnected - S_unconnected,
"Size effect in connected (L - S)" = L_connected - S_connected,
"Size effect in connected (M - S)" = M_connected - S_connected)) %>%
as.data.frame() %>%
mutate(p.value = round(p.value, digits = n_of_digits),
estimate = round(estimate, digits = n_of_digits),
SE = round(SE, digits = n_of_digits),
df = round(df, digits = n_of_digits),
z.ratio = round(z.ratio, digits = n_of_digits),
e = "",
e = ifelse(p.value > 0.1,
"",
e),
e = ifelse(p.value < 0.05,
"*",
e),
e = ifelse(p.value < 0.01,
"**",
e),
e = ifelse(p.value < 0.001,
"***",
e)) %>%
rename(" " = e)
contrasts
## contrast estimate SE df z.ratio p.value
## 1 Small connection effect -0.833 0.182 Inf -4.581 0.000 ***
## 2 Medium connection effect -0.068 0.147 Inf -0.460 0.645
## 3 Large connection effect -0.553 0.148 Inf -3.747 0.000 ***
## 4 Size effect in unconnected (L - S) 0.481 0.146 Inf 3.296 0.001 **
## 5 Size effect in unconnected (M - S) 0.213 0.150 Inf 1.414 0.157
## 6 Size effect in connected (L - S) 0.760 0.183 Inf 4.147 0.000 ***
## 7 Size effect in connected (M - S) 0.978 0.179 Inf 5.458 0.000 ***
We know that the connection of heterotrophic ecosystems to autotrophic ecosystems changed their biodiversity and biomass. However, we don’t know if this change is due to community composition and how this could be explained through the composition of heterotrophic when not connected. Here, we plot how dominant species were in small/medium/large heterotrophic ecosystems when unconnected and when connected. The dominance is expressed as percentage of biomass in the species. First we plot species dominance for each ecosystem type. Then, we plot the effect size of the dominance between connected and unconnected. We use two effect sizes: Hedge’s d-a more accurate effect size when handling zeros in the treatmtnet and/or control-and Log Response Ratio-a more easy to understand effect size.
print_dominance("Small heterotrophic unconnected")
print_dominance("Small heterotrophic connected")
for(time_point_i in 2:4){
print(paste("Time point ", time_point_i))
p = ds_species_effect_sizes_d %>%
filter(ecosystem_type == "Small heterotrophic connected",
time_point == time_point_i,
species != "Eug") %>%
ggplot(aes(x = species,
y = effect_size)) +
geom_pointrange(aes(ymin = lower_95_CI, ymax = upper_95_CI)) +
geom_hline(yintercept = 0, linetype = "dotted") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"))
print(p)
}
## [1] "Time point 2"
## [1] "Time point 3"
## [1] "Time point 4"
print_dominance("Medium heterotrophic unconnected")
print_dominance("Medium heterotrophic connected")
for(time_point_i in 2:4){
print(paste("Time point ", time_point_i))
p = ds_species_effect_sizes_d %>%
filter(ecosystem_type == "Medium heterotrophic connected",
time_point == time_point_i,
species != "Eug") %>%
ggplot(aes(x = species,
y = effect_size)) +
geom_pointrange(aes(ymin = lower_95_CI, ymax = upper_95_CI)) +
geom_hline(yintercept = 0, linetype = "dotted") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"))
print(p)
}
## [1] "Time point 2"
## [1] "Time point 3"
## [1] "Time point 4"
print_dominance("Large heterotrophic unconnected")
print_dominance("Large heterotrophic connected")
for(time_point_i in 2:4){
print(paste("Time point ", time_point_i))
p = ds_species_effect_sizes_d %>%
filter(ecosystem_type == "Large heterotrophic connected",
time_point == time_point_i,
species != "Eug") %>%
ggplot(aes(x = species,
y = effect_size)) +
geom_pointrange(aes(ymin = lower_95_CI, ymax = upper_95_CI)) +
geom_hline(yintercept = 0, linetype = "dotted") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"))
print(p)
}
## [1] "Time point 2"
## [1] "Time point 3"
## [1] "Time point 4"
The connection affected community composition in small, medium, and large heterotrophic patches. In small heterotrophic patches, the connection increased the dominance of Pau (t3) and decreased the one of Col (t3-4) and Pca (t4). In the medium heterotrophic patches, the connection increased the dominance of Ble (t2-3) and Pau (t4). In the large heterotrophic patches, the connection increased the dominance of Ble (t2) and Col (t2).
print_dominance("Small heterotrophic unconnected")
print_dominance("Small heterotrophic connected")
for(time_point_i in 2:4){
print(paste("Time point ", time_point_i))
p = ds_species_effect_sizes_LRR %>%
filter(ecosystem_type == "Small heterotrophic connected",
time_point == time_point_i,
species != "Eug") %>%
ggplot(aes(x = species,
y = effect_size)) +
geom_pointrange(aes(ymin = lower_95_CI, ymax = upper_95_CI)) +
geom_hline(yintercept = 0, linetype = "dotted") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"))
print(p)
}
## [1] "Time point 2"
## [1] "Time point 3"
## [1] "Time point 4"
print_dominance("Medium heterotrophic unconnected")
print_dominance("Medium heterotrophic connected")
for(time_point_i in 2:4){
print(paste("Time point ", time_point_i))
p = ds_species_effect_sizes_LRR %>%
filter(ecosystem_type == "Medium heterotrophic connected",
time_point == time_point_i,
species != "Eug") %>%
ggplot(aes(x = species,
y = effect_size)) +
geom_pointrange(aes(ymin = lower_95_CI, ymax = upper_95_CI)) +
geom_hline(yintercept = 0, linetype = "dotted") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"))
print(p)
}
## [1] "Time point 2"
## [1] "Time point 3"
## [1] "Time point 4"
print_dominance("Large heterotrophic unconnected")
print_dominance("Large heterotrophic connected")
for(time_point_i in 2:4){
print(paste("Time point ", time_point_i))
p = ds_species_effect_sizes_LRR %>%
filter(ecosystem_type == "Large heterotrophic connected",
time_point == time_point_i,
species != "Eug") %>%
ggplot(aes(x = species,
y = effect_size)) +
geom_pointrange(aes(ymin = lower_95_CI, ymax = upper_95_CI)) +
geom_hline(yintercept = 0, linetype = "dotted") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"))
print(p)
}
## [1] "Time point 2"
## [1] "Time point 3"
## [1] "Time point 4"
The connection in small ecosystems increases Ble (t3) and Pau and Cep (t4). In medium ecosystems it increases Ble (t3), Spi (t4), and decreases Cep and Col (t5). In large ecosystems it increases Col and Ble (t2), and increases Spi (t5).
We want to know whether there was a correlation between biodiversity (richness/shannon/eveness) and productivity. We include all the time points in all the heterotrophic ecosystems (small/medium/large, connected/unconnected).
ds_ecosystems %>%
filter(trophic_type == "heterotrophic") %>%
ggplot(aes(x = species_richness,
y = bioarea_mm2_per_ml)) +
geom_point() +
xlim(0, length(protist_species)) +
labs(x = axis_names$axis_name[axis_names$variable == "species_richness"],
y = axis_names$axis_name[axis_names$variable == "bioarea_mm2_per_ml"]) +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"))
ds_ecosystems %>%
filter(trophic_type == "heterotrophic") %>%
ggplot(aes(x = shannon,
y = bioarea_mm2_per_ml)) +
geom_point() +
labs(x = axis_names$axis_name[axis_names$variable == "shannon"],
y = axis_names$axis_name[axis_names$variable == "bioarea_mm2_per_ml"]) +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"))
ds_ecosystems %>%
filter(trophic_type == "heterotrophic",
is.na(evenness_pielou) != TRUE) %>%
ggplot(aes(x = evenness_pielou,
y = bioarea_mm2_per_ml)) +
geom_point() +
labs(x = axis_names$axis_name[axis_names$variable == "evenness_pielou"],
y = axis_names$axis_name[axis_names$variable == "bioarea_mm2_per_ml"]) +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"))
# --- SET RESULT PARAMETERS --- #
treatment_colours = c("Small heterotrophic connected"= "#3182bd",
"Medium heterotrophic connected"= "#3182bd",
"Large heterotrophic connected" = "#3182bd",
"Small autotrophic connected" = "#2ca25f",
"Medium autotrophic connected" = "#2ca25f",
"Large autotrophic connected" = "#2ca25f",
"Small heterotrophic unconnected"= "#3182bd",
"Medium heterotrophic unconnected"= "#3182bd",
"Large heterotrophic unconnected" = "#3182bd",
"Small autotrophic unconnected" = "#2ca25f",
"Medium autotrophic unconnected" = "#2ca25f",
"Large autotrophic unconnected" = "#2ca25f",
"Small heterotrophic"= "#3182bd",
"Medium heterotrophic"= "#3182bd",
"Large heterotrophic" = "#3182bd",
"Small autotrophic" = "#2ca25f",
"Medium autotrophic" = "#2ca25f",
"Large autotrophic" = "#2ca25f",
"AD" = "#5ab4ac",
"ED" = "#969696",
"HD" = "#d8b365",
"AD connected" = "#5ab4ac",
"ED connected" = "#969696",
"HD connected" = "#d8b365",
"AD unconnected" = "#5ab4ac",
"ED unconnected" = "#969696",
"HD unconnected" = "#d8b365")
Figure 2. The effect of the autotrophic-heterotrophic spatial feedback on meta-ecosystem biomass was tuned by patch size. The effects of the spatial feedback on total meta-ecosystem biomass were positive in Autotrophic Dominated meta-ecosystems (they had higher total bioarea than Autotrophic Dominated isolated), negative in Heterotrophic Dominated meta-ecosystems (they had lower total bioarea than Heterotrophic Dominated isolated), and non-significant in Equally Dominated meta-ecosystems (they had the same total bioarea than Equally Dominated isolated). Heterotrophic-dominated meta-ecosystems: meta-ecosystems with one big heterotrophic and one small autotrophic patch. Autotrophic-dominated meta-ecosystems: meta-ecosystems with one big autotrophic and one small heterotrophic patch. Heterotrophic-dominated isolated: systems composed of one big heterotrophic and one small autotrophic isolated patch. Autotrophic-dominated isolated: systems with one big autotrophic and one small heterotrophic isolated patch.
# --- CREATE THE META-ECOSYSTEM PLOT FOR THE PAPER --- #
# Generate the PNG image where to save the plot
png(file = here("3_results", "figures", "paper", "metaecosystems_1.png"),
width = paper_width,
height = paper_height,
units = paper_units,
res = paper_res)
# Create plot
p = plot.metaecos.points(data = ds_metaecosystems,
response_variable = "total_metaecosystem_bioarea_mm2")
# Modify the plot to be saved using ggarrange
ggpubr::ggarrange(p +
theme(plot.margin = unit(c(ggarrange_margin_left,
ggarrange_margin_right,
ggarrange_margin_bottom,
ggarrange_margin_left),
"cm")) +
scale_x_continuous(breaks = unique(ds_ecosystems$day)),
align = "v",
label.x = 0.1,
label.y = 0.8)
# Close the current graphics device to properly save the PNG image
dev.off()
# --- SHOW THE META-ECOSYSTEM PLOT FOR THE PAPER --- #
p
Figure 3. The connection to another patch increased the biomass of the autotrophic ecosystems and decreased the biomass of the heterotrophic ecosystems in both (a) Autotrophic Dominated and (b) Heterotrophic Dominated meta-ecosystems
# --- CONSTRUCT ECOSYSTEM BIOMASS PLOTS --- #
# Set parameters
response_variable = "bioarea_mm2_per_ml"
ecosystem_size_and_trophy_p_1 = c("Large autotrophic",
"Small heterotrophic")
ecosystem_size_and_trophy_p_2 = c("Large heterotrophic",
"Small autotrophic")
legend_row_n_input = 2
y_min = 0
y_max = 21
# Prepare data for plotting
data_plot_1 = ds_ecosystems %>%
filter(ecosystem_size_and_trophy %in% ecosystem_size_and_trophy_p_1)
data_plot_2 = ds_ecosystems %>%
filter(ecosystem_size_and_trophy %in% ecosystem_size_and_trophy_p_2)
# Construct plots
p_1 = plot.ecosystems.points(data_plot_1,
response_variable,
legend_row_n_input) +
theme(plot.margin = unit(c(ggarrange_margin_left,
ggarrange_margin_right,
ggarrange_margin_bottom,
ggarrange_margin_left),
"cm")) +
ylim(y_min, y_max)
p_2 = plot.ecosystems.points(data_plot_2,
response_variable,
legend_row_n_input) +
theme(plot.margin = unit(c(ggarrange_margin_left,
ggarrange_margin_right,
ggarrange_margin_bottom,
ggarrange_margin_left),
"cm")) +
ylim(y_min, y_max)
# Combine plots
p_combined = ggarrange(p_1 +
rremove("xlab") +
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank()),
p_2 +
scale_x_continuous(breaks = unique(data_plot_2$day)),
heights = c(0.8, 0.8, 1),
nrow = 2,
align = "v",
labels = c("AD", "HD"),
label.x = 0.07,
label.y = 0.77)
# --- SHOW ECOSYSTEM BIOMASS PLOTS --- #
p_combined
# --- SAVE ECOSYSTEM BIOMASS PLOTS --- #
# Generate the PNG image where to save the plot
png(file = here("3_results", "figures", "paper", "ecosystems_biomass.png"),
width = paper_width,
height = paper_height,
units = paper_units,
res = paper_res)
# Save image to the file
p_combined
# Close the current graphics device to properly save the PNG image
dev.off()
## Time difference of 54.49859 secs
Create plots for presentations on how meta-ecosystem biomass changed across connected and unconnected meta-ecosystem types. Start from plotting an empty figures and then show one line at the time.
# --- SET PARAMETERS FOR PLOTTING --- #
response_variable = "total_metaecosystem_bioarea_mm2"
metaeco_type_n_connection_selected = c("ED unconnected",
"ED connected",
"AD unconnected",
"AD connected",
"HD unconnected",
"HD connected")
x_min = 0
x_max = sampling_days[length(sampling_days)]
y_min = 50
y_max = 750
plot_label_x = 0.1
plot_label_y = 0.8
# --- CREATE AN EMPTY PLOT --- #
# Set parameters
connections_selected = ""
types_selected = ""
# Generate the PNG image where to save the plot
png(file = here("3_results",
"figures",
"presentations",
"metaecosystems_0.png"),
width = presentation_figure_width,
height = presentation_figure_height,
units = presentation_figure_units,
res = presentation_figure_res)
# Prepare data for plotting
data_for_plotting = ds_metaecosystems %>%
filter(!is.na(!!sym(response_variable)))
# Create plot
p = data_for_plotting %>%
ggplot(aes(x = day,
y = get(response_variable))) +
geom_point(stat = "summary",
fun = "mean",
position = position_dodge(dodging),
size = presentation_treatment_points_size) +
scale_x_continuous(breaks = sampling_days,
limits = c(x_min, x_max)) +
ylim(y_min, y_max) +
labs(x = axis_names$axis_name[axis_names$variable == "day"],
y = axis_names$axis_name[axis_names$variable == response_variable]) +
font("xlab", size = presentation_labels_size) +
font("ylab", size = presentation_labels_size) +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"),
axis.title.x = element_text(size = presentation_labels_size),
axis.title.y = element_text(size = presentation_labels_size),
axis.text.x = element_text(size = presentation_labels_size),
axis.text.y = element_text(size = presentation_labels_size),
plot.margin = unit(c(ggarrange_margin_left,
ggarrange_margin_right,
ggarrange_margin_bottom,
ggarrange_margin_left),
"cm")) +
geom_rect(xmin = grey_background_xmin,
xmax = grey_background_xmax,
ymin = grey_background_ymin,
ymax = grey_background_ymax,
fill = grey_background_fill,
alpha = grey_background_alpha,
color = grey_background_color) +
geom_vline(xintercept = resource_flow_days,
linetype = resource_flow_line_type,
color = resource_flow_line_colour,
linewidth = resource_flow_line_width)
# Save the plot in the same way you will save the following plots using ggarrange
ggpubr::ggarrange(p,
align = "v",
label.x = plot_label_x,
label.y = plot_label_y) %>%
print()
# Close the current graphics device to properly save the PNG image
dev.off()
# --- CREATE PLOTS LINE BY LINE --- #
# Plot filled plots, adding to every plot a new line.
for(i in 1:length(metaeco_type_n_connection_selected)) {
# Generate the PNG image where to save the plot
png(file = here("3_results",
"figures",
"presentations",
paste0("metaecosystems_", i, ".png")),
width = presentation_figure_width,
height = presentation_figure_height,
units = presentation_figure_units,
res = presentation_figure_res)
# Prepare data for plotting
data_for_plotting = ds_metaecosystems %>%
filter(metaeco_type_n_connection %in% metaeco_type_n_connection_selected[1:i],
!is.na(!!sym(response_variable))) %>%
summarySE(measurevar = response_variable,
groupvars = c("day", "metaecosystem_type", "connection"))
# Create plot
p = data_for_plotting %>%
ggplot(aes(x = day,
y = get(response_variable),
group = interaction(day, metaecosystem_type, connection),
color = metaecosystem_type,
linetype = connection)) +
# Points
geom_point(stat = "summary",
fun = "mean",
position = position_dodge(dodging),
size = presentation_treatment_points_size) +
geom_errorbar(aes(ymax = get(response_variable) + ci,
ymin = get(response_variable) - ci),
width = width_errorbar,
position = position_dodge(dodging)) +
# Lines
geom_line(stat = "summary",
fun = "mean",
aes(group = interaction(metaecosystem_type, connection)),
position = position_dodge(dodging),
linewidth = presentation_treatment_linewidth) +
scale_linetype_manual(values = treatment_linetypes) +
# Axes & legend
labs(x = axis_names$axis_name[axis_names$variable == "day"],
y = axis_names$axis_name[axis_names$variable == response_variable],
color = "") +
guides(color = "none",
linetype = "none") +
xlim(x_min, x_max) +
ylim(y_min, y_max) +
scale_x_continuous(breaks = unique(ds_metaecosystems$day)) +
scale_color_manual(values = treatment_colours) +
guides(color = guide_legend(order = 1,
title = NULL),
linetype = guide_legend(order = 2,
title = NULL)) +
# Extra graphic elements
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = "none",
legend.key.width = unit(legend_width_cm, "cm"),
axis.title.x = element_text(size = presentation_labels_size),
axis.title.y = element_text(size = presentation_labels_size),
axis.text.x = element_text(size = presentation_labels_size),
axis.text.y = element_text(size = presentation_labels_size)) +
geom_rect(xmin = grey_background_xmin,
xmax = grey_background_xmax,
ymin = grey_background_ymin,
ymax = grey_background_ymax,
fill = grey_background_fill,
alpha = grey_background_alpha,
color = grey_background_color) +
geom_vline(xintercept = resource_flow_days,
linetype = resource_flow_line_type,
color = resource_flow_line_colour,
linewidth = resource_flow_line_width)
# Save the plot in the same way you will save the following plots using ggarrange
ggpubr::ggarrange(p,
align = "v",
label.x = plot_label_x,
label.y = plot_label_y) %>%
print()
# Close the current graphics device to properly save the PNG image
dev.off()
}
Create plots for presentations on how ecosystem biomass changed across connected and unconnected types. Start from plotting an empty figures and then show one line at the time.
metaecosystem_type_selected = "AD"
# --- SET PARAMETERS FOR PLOTTING --- #
response_variable = "bioarea_mm2_per_ml"
x_min = 0
x_max = sampling_days[length(sampling_days)]
y_min = -1
y_max = 22
# --- PREPARE DATA FOR PLOTTING --- #
data_for_plotting = ds_ecosystems %>%
filter(metaecosystem_type == metaecosystem_type_selected)
# --- GET ECOSYSTEM TYPES TO PLOT --- #
ecosystem_type_selected = data_for_plotting %>%
pull(ecosystem_type) %>%
unique()
# --- CREATE AN EMPTY PLOT --- #
# Generate the PNG image where to save the plot
png(file = here("3_results",
"figures",
"presentations",
paste0(metaecosystem_type_selected, "_ecosystems_0.png")),
width = presentation_figure_width,
height = presentation_figure_height,
units = presentation_figure_units,
res = presentation_figure_res)
# Prepare data for plotting
data_for_plotting_2 = data_for_plotting %>%
filter(ecosystem_type == "",
!is.na(!!sym(response_variable)))
# Create plot
p = data_for_plotting_2 %>%
ggplot(aes(x = day,
y = get(response_variable))) +
scale_x_continuous(breaks = sampling_days,
limits = c(x_min, x_max)) +
ylim(y_min, y_max) +
labs(x = axis_names$axis_name[axis_names$variable == "day"],
y = axis_names$axis_name[axis_names$variable == response_variable]) +
geom_vline(xintercept = resource_flow_days,
linetype = resource_flow_line_type,
color = resource_flow_line_colour,
linewidth = resource_flow_line_width) +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"),
axis.title.x = element_text(size = presentation_labels_size),
axis.title.y = element_text(size = presentation_labels_size),
axis.text.x = element_text(size = presentation_labels_size),
axis.text.y = element_text(size = presentation_labels_size),
plot.margin = unit(c(ggarrange_margin_left,
ggarrange_margin_right,
ggarrange_margin_bottom,
ggarrange_margin_left),
"cm")) +
font("xlab", size = presentation_labels_size) +
font("ylab", size = presentation_labels_size)
# Show plot
p
# Give the plot a ggpubr format
ggpubr::ggarrange(p,
align = "v",
label.x = 0.1,
label.y = 0.8) %>%
print()
# Close the current graphics device to properly save the PNG image
dev.off()
# --- CREATE PLOTS LINE BY LINE --- #
# Plot filled plots, adding to every plot a new line.
for(i in 1:length(ecosystem_type_selected)) {
# Prepare data for plotting
data_for_plotting_2 = data_for_plotting %>%
filter(ecosystem_type %in% ecosystem_type_selected[1:i],
!is.na(!!sym(response_variable))) %>%
summarySE(measurevar = response_variable,
groupvars = c("day", "ecosystem_type", "connection"))
# Create plot
p = data_for_plotting_2 %>%
ggplot(aes(x = day,
y = get(response_variable),
group = interaction(day, ecosystem_type, connection),
color = ecosystem_type,
linetype = connection)) +
# Points
geom_point(stat = "summary",
fun = "mean",
position = position_dodge(dodging),
size = presentation_treatment_points_size) +
geom_errorbar(aes(ymax = get(response_variable) + ci,
ymin = get(response_variable) - ci),
width = width_errorbar,
position = position_dodge(dodging)) +
# Lines
geom_line(stat = "summary",
fun = "mean",
aes(group = interaction(ecosystem_type, connection)),
position = position_dodge(dodging),
linewidth = presentation_treatment_linewidth) +
scale_linetype_manual(values = treatment_linetypes) +
# Axes & legend
labs(x = axis_names$axis_name[axis_names$variable == "day"],
y = axis_names$axis_name[axis_names$variable == response_variable],
color = "") +
guides(color = "none",
linetype = "none") +
xlim(x_min, x_max) +
ylim(y_min, y_max) +
scale_x_continuous(breaks = unique(data_for_plotting_2$day)) +
scale_color_manual(values = treatment_colours) +
guides(color = guide_legend(order = 1,
title = NULL),
linetype = guide_legend(order = 2,
title = NULL)) +
# Extra graphic elements
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = "none",
legend.key.width = unit(legend_width_cm, "cm"),
axis.title.x = element_text(size = presentation_labels_size),
axis.title.y = element_text(size = presentation_labels_size),
axis.text.x = element_text(size = presentation_labels_size),
axis.text.y = element_text(size = presentation_labels_size)) +
geom_rect(xmin = grey_background_xmin,
xmax = grey_background_xmax,
ymin = grey_background_ymin,
ymax = grey_background_ymax,
fill = grey_background_fill,
alpha = grey_background_alpha,
color = grey_background_color) +
geom_vline(xintercept = resource_flow_days,
linetype = resource_flow_line_type,
color = resource_flow_line_colour,
linewidth = resource_flow_line_width)
# Give the plot a ggpubr format
p = ggpubr::ggarrange(p,
align = "v",
label.x = 0.1,
label.y = 0.8) %>%
print()
# Generate the PNG image where to save the plot
png(file = here("3_results",
"figures",
"presentations",
paste0(metaecosystem_type_selected, "_ecosystems_", i, ".png")),
width = presentation_figure_width,
height = presentation_figure_height,
units = presentation_figure_units,
res = presentation_figure_res)
# Save image to the file
print(p)
# Close the current graphics device to properly save the PNG image
dev.off()
}
Create plots for presentations on how ecosystem evenness changed across connected and unconnected meta-ecosystem types. Start from plotting an empty figures and then show one line at the time.
metaecosystem_type_selected = "HD"
# --- SET PARAMETERS FOR PLOTTING --- #
response_variable = "bioarea_mm2_per_ml"
x_min = 0
x_max = sampling_days[length(sampling_days)]
y_min = -1
y_max = 22
# --- PREPARE DATA FOR PLOTTING --- #
data_for_plotting = ds_ecosystems %>%
filter(metaecosystem_type == metaecosystem_type_selected)
# --- GET ECOSYSTEM TYPES TO PLOT --- #
ecosystem_type_selected = data_for_plotting %>%
pull(ecosystem_type) %>%
unique()
# --- CREATE AN EMPTY PLOT --- #
# Generate the PNG image where to save the plot
png(file = here("3_results",
"figures",
"presentations",
paste0(metaecosystem_type_selected, "_ecosystems_0.png")),
width = presentation_figure_width,
height = presentation_figure_height,
units = presentation_figure_units,
res = presentation_figure_res)
# Prepare data for plotting
data_for_plotting_2 = data_for_plotting %>%
filter(ecosystem_type == "",
!is.na(!!sym(response_variable)))
# Create plot
p = data_for_plotting_2 %>%
ggplot(aes(x = day,
y = get(response_variable))) +
scale_x_continuous(breaks = sampling_days,
limits = c(x_min, x_max)) +
ylim(y_min, y_max) +
labs(x = axis_names$axis_name[axis_names$variable == "day"],
y = axis_names$axis_name[axis_names$variable == response_variable]) +
geom_vline(xintercept = resource_flow_days,
linetype = resource_flow_line_type,
color = resource_flow_line_colour,
linewidth = resource_flow_line_width) +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"),
axis.title.x = element_text(size = presentation_labels_size),
axis.title.y = element_text(size = presentation_labels_size),
axis.text.x = element_text(size = presentation_labels_size),
axis.text.y = element_text(size = presentation_labels_size),
plot.margin = unit(c(ggarrange_margin_left,
ggarrange_margin_right,
ggarrange_margin_bottom,
ggarrange_margin_left),
"cm")) +
font("xlab", size = presentation_labels_size) +
font("ylab", size = presentation_labels_size)
# Show plot
p
# Give the plot a ggpubr format
ggpubr::ggarrange(p,
align = "v",
label.x = 0.1,
label.y = 0.8) %>%
print()
# Close the current graphics device to properly save the PNG image
dev.off()
# --- CREATE PLOTS LINE BY LINE --- #
# Plot filled plots, adding to every plot a new line.
for(i in 1:length(ecosystem_type_selected)) {
# Prepare data for plotting
data_for_plotting_2 = data_for_plotting %>%
filter(ecosystem_type %in% ecosystem_type_selected[1:i],
!is.na(!!sym(response_variable))) %>%
summarySE(measurevar = response_variable,
groupvars = c("day", "ecosystem_type", "connection"))
# Create plot
p = data_for_plotting_2 %>%
ggplot(aes(x = day,
y = get(response_variable),
group = interaction(day, ecosystem_type, connection),
color = ecosystem_type,
linetype = connection)) +
# Points
geom_point(stat = "summary",
fun = "mean",
position = position_dodge(dodging),
size = presentation_treatment_points_size) +
geom_errorbar(aes(ymax = get(response_variable) + ci,
ymin = get(response_variable) - ci),
width = width_errorbar,
position = position_dodge(dodging)) +
# Lines
geom_line(stat = "summary",
fun = "mean",
aes(group = interaction(ecosystem_type, connection)),
position = position_dodge(dodging),
linewidth = presentation_treatment_linewidth) +
scale_linetype_manual(values = treatment_linetypes) +
# Axes & legend
labs(x = axis_names$axis_name[axis_names$variable == "day"],
y = axis_names$axis_name[axis_names$variable == response_variable],
color = "") +
guides(color = "none",
linetype = "none") +
xlim(x_min, x_max) +
ylim(y_min, y_max) +
scale_x_continuous(breaks = unique(data_for_plotting_2$day)) +
scale_color_manual(values = treatment_colours) +
guides(color = guide_legend(order = 1,
title = NULL),
linetype = guide_legend(order = 2,
title = NULL)) +
# Extra graphic elements
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = "none",
legend.key.width = unit(legend_width_cm, "cm"),
axis.title.x = element_text(size = presentation_labels_size),
axis.title.y = element_text(size = presentation_labels_size),
axis.text.x = element_text(size = presentation_labels_size),
axis.text.y = element_text(size = presentation_labels_size)) +
geom_rect(xmin = grey_background_xmin,
xmax = grey_background_xmax,
ymin = grey_background_ymin,
ymax = grey_background_ymax,
fill = grey_background_fill,
alpha = grey_background_alpha,
color = grey_background_color) +
geom_vline(xintercept = resource_flow_days,
linetype = resource_flow_line_type,
color = resource_flow_line_colour,
linewidth = resource_flow_line_width)
# Give the plot a ggpubr format
p = ggpubr::ggarrange(p,
align = "v",
label.x = 0.1,
label.y = 0.8) %>%
print()
# Generate the PNG image where to save the plot
png(file = here("3_results",
"figures",
"presentations",
paste0(metaecosystem_type_selected, "_ecosystems_", i, ".png")),
width = presentation_figure_width,
height = presentation_figure_height,
units = presentation_figure_units,
res = presentation_figure_res)
# Save image to the file
print(p)
# Close the current graphics device to properly save the PNG image
dev.off()
}
To disturb ecosystems in the past experiment (PatchSize), we inserted ecosystem sub-samples into 50-ml falcon tubes (here called “tubes”), inserted tubes into a tube rack, and then microwaved the rack. However, this process is time demanding. Here, we explore the possibility of (i) using a laboratory oven to replace the microwave and (ii) whether it would be more appropriate to use tubes or 250-ml Schott bottles (here called “bottles”); which were tested by measuring heating and evaporation rates of deionised water in tubes or bottles. I put into a 90 °C oven tubes with 7.5 or 37.5 ml water and bottles with 200 ml water (see lab book for how fast they heated up), all replicated ten-fold,and measured the temperature of one replicate every 30 minutes. The container whose temperature was measured was set aside and another replicate was measured the following 30 minutes. After 125 minutes, I took all the remaining replicates and measured their evaporation, without letting them cool down. Then, I repeated the process but increasing the oven temperature to 100 °C, measuring containers every 20 minutes, and measuring evaporation rates after 90 minutes.
colour_90_degrees = "#4daf4a"
colour_100_degrees = "#e41a1c"
colour_7.5_tubes = "#d8b365"
colour_37.5_tubes = "#5ab4ac"
ds_OvenTest_1 = read.csv(here("1_data", "tests", "OvenTest", "OvenTest1_data.csv"), header = TRUE) %>%
mutate(water_initial_weight = tube_n_water_weight - tube_weight) %>%
mutate(evaporation_weight = water_initial_weight - water_after_oven_weight) %>%
mutate(oven_temperature = as.character(oven_temperature))
ds_OvenTest_1$treatment = paste(ds_OvenTest_1$container, ds_OvenTest_1$water_pipetted, 'ml')
ds_OvenTest_1oven_temperature = factor(ds_OvenTest_1$oven_temperature,levels=c('90 °C for 125 minutes', '100 °C for 90 minutes'))
ds_OvenTest_1$treatment = factor(ds_OvenTest_1$treatment,levels=c('tube 7.5 ml', 'tube 37.5 ml', 'bottle 200 ml'))
ds_OvenTest_1 %>%
filter (taken_out_early == "no") %>%
drop_na(evaporation_weight) %>%
mutate(oven_temperature = factor(oven_temperature,
levels = c("90 °C for 125 minutes",
"100 °C for 90 minutes"))) %>%
ggplot (aes(x = treatment,
y = evaporation_weight,
fill = oven_temperature)) +
geom_boxplot() +
scale_fill_manual(values = c(colour_90_degrees,
colour_100_degrees)) +
labs(x = "",
y = "Water evaporation (g)",
fill = "") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"))
After presenting the results to Florian, we agreed to use falcon tubes-as they occupy less space-and to remeasure evaporation and heating rates to make sure that there isn’t too much variation across replicates. Therefore, I conducted another test: four 25-tube racks were put into a [write how hot the oven was] °C oven for 105 minutes. Two racks with tubes with 7.5 ml water and the other two with tubes with 37.5 ml water. After 30 minutes and 60 minutes I checked the temperature of 5 tubes (4 in the corners, 1 in the centre) of each rack. After 105 minutes, I checked the water evaporation of the remaning tubes (after letting the tubes cool down for around 90 minutes). The following plots show how fast tubes heated up and evaporated.
ds_OvenTest_2 = read.csv(here("1_data", "tests", "OvenTest", "OvenTest2_data.csv"), header = TRUE) %>%
mutate(weight_water_beginning = tube_n_water_weight - tube_weight) %>%
mutate(evaporation_weight = weight_water_beginning - water_weight_after_heating)
ds_OvenTest_2 %>%
rename("30" = temperature_after_30_min) %>%
rename("60" = temperature_after_60_min) %>%
pivot_longer(7:8, names_to = "time", values_to = "temperature") %>%
mutate(water_volume_added = factor(water_volume_added,
levels = c("7.5", "37.5"),
ordered = TRUE)) %>%
drop_na(temperature) %>%
ggplot(aes(x = time,
y = temperature,
fill = water_volume_added)) +
geom_boxplot() +
scale_fill_manual(values = c(colour_7.5_tubes, colour_37.5_tubes)) +
labs(x = "Time (min)",
y = "Temperature (°C)",
fill='Water volume (ml)') +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = legend_position,
legend.key.width = unit(legend_width_cm, "cm"))
ds_OvenTest_2 %>%
drop_na(evaporation_weight) %>%
mutate(water_volume_added = factor(water_volume_added,
levels = c("7.5", "37.5"),
ordered = TRUE)) %>%
ggplot(aes(x = as.factor(water_volume_added),
y = evaporation_weight,
fill = as.factor(water_volume_added))) +
labs(x = "Ecosystem volume (ml)",
y = "Evaporation (ml)") +
geom_boxplot() +
scale_fill_manual(values = c(colour_7.5_tubes, colour_37.5_tubes)) +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = "none",
legend.key.width = unit(legend_width_cm, "cm"))
These results show us how much water was lost after heating it up in the oven and pouring it into a Becker to measure it. However, it can be that some of the water was lost because it got stuck to the walls of the tube and could not be retrieved. To find out how much water is left in the tube after the pouring, I performed an additional test. I filled tubes with 7.5 or 37.5 ml, weighed the water inside, poured the water out, and reweighed the water inside.
ds_PooringTest = read.csv(here("1_data", "tests", "PooringTest.csv"), header = TRUE)
ds_PooringTest%>%
mutate(left_in_tube = tube_after_water_g - tube_g,
water_in_tube_ml = factor(water_in_tube_ml,
levels = c("7.5", "37.5"),
ordered = TRUE)) %>%
ggplot(aes(x = reorder(water_in_tube_ml, sort(as.numeric(water_in_tube_ml))),
y = left_in_tube,
fill = water_in_tube_ml)) +
geom_boxplot() +
scale_fill_manual(values = c(colour_7.5_tubes, colour_37.5_tubes)) +
labs(x = "Water in and out tube (ml)",
y = "Water in tube after pooring (g)") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = "none",
legend.key.width = unit(legend_width_cm, "cm"))
Euglena gracilis (Eug) is an important part of our system, as it allows the fixation of carbon into the meta-ecosystem and creates differences in resources between ecosystems with and without it. Because Euglena is so important in meta-ecosystem dynamics, we want it to grow to reasonable densities in our ecosystems. However, in our past experiment (PatchSize), Euglena grew only to low densities. We suspect that the falcon tubes were too opaque and that the foam board covered the cultures, causing Euglena to grow slowly and be overcompeted. Therefore, before performing this experiment (AHSize), we explored whether 45-ml cell flasks, 250-ml Schott bottles, or well plates would be a better alternative to 50-ml falcon tubes. First, we compared the growth of Euglena gracilis in bottles (100 ml ecosystems) and well plates (7.5 ml ecosystems) to tubes (7.5 and 37.5 ml ecosystems). Results (not displayed here) showed that well plates allowed Euglena to grow better. Second, we compared cell flasks to well plates (both had 7.5 ml ecosystems and six replicates). Videos were then analysed with the BEMOVI package set with a lower threshold of ImageJ of 30.
### --- IMPORT --- ###
load(here("1_data", "tests", "EugGrowthTest", "t0.RData")); t0 = pop_output
load(here("1_data", "tests", "EugGrowthTest", "t1.RData")); t1 = pop_output
load(here("1_data", "tests", "EugGrowthTest", "t2.RData")); t2 = pop_output
load(here("1_data", "tests", "EugGrowthTest", "t3.RData")); t3 = pop_output
rm(pop_output)
### --- TIDY --- ####
t0_wells = t0 %>%
mutate(container = "well")
t0_flasks = t0 %>%
mutate(container = "flask")
t0 = rbind(t0_wells, t0_flasks)
ds_eug = rbind(t0,t1,t2,t3); rm(t1,t2,t3)
### --- PLOT --- ###
ds_eug %>%
ggplot(aes(x = day,
y = indiv_per_volume*1000,
group = interaction(day, container),
fill = container)) +
geom_boxplot() +
labs(x = "Time (day)",
y = "Eug abundance (indiv/ml)",
fill = "") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = c(.2, .9),
legend.justification = c("right", "top"),
legend.box.just = "right",
legend.margin = margin(6, 6, 6, 6))
## Warning: A numeric `legend.position` argument in `theme()` was deprecated in ggplot2
## 3.5.0.
## ℹ Please use the `legend.position.inside` argument of `theme()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
If you want to change a certain part of the code using the following code in Unix:
#Rmd script
cd /Users/ema/Documents/GitHub/AHSize/r_files; sed -i '' 's/old_string/new_string/g' *.Rmd
#R script
cd /Users/ema/Documents/GitHub/AHSize/r_files/functions; sed -i '' 's/old_string/new_string/g' *.R
If you want to share a dataset and get a reproducible object, use the following R code:
dput(data)
This are 20 random columns of ds_metaecosystems that you can use to input into chatGPT to give it an idea of what the structure of your data is.
ds_metaecosystems %>%
sample_n(20,
replace = FALSE) %>%
dput()
## structure(list(time_point = c(1L, 4L, 0L, 0L, 3L, 4L, 1L, 4L,
## 2L, 3L, 0L, 4L, 0L, 0L, 4L, 3L, 4L, 3L, 0L, 4L), day = c(5, 26,
## 0, 0, 19, 26, 5, 26, 12, 19, 0, 26, 0, 0, 26, 19, 26, 19, 0,
## 26), system_nr = c(1010L, 1042L, 1001L, 1057L, 1022L, 1008L,
## 39L, 1013L, 1054L, 1015L, 1022L, 1062L, 1011L, 1053L, 33L, 1064L,
## 1064L, 1071L, 1030L, 1067L), ecosystems_combined = c("7|25",
## "29|2", "6|21", "17|12", "10|22", "7|23", "47|48", "8|23", "16|14",
## "8|25", "10|22", "18|12", "8|21", "16|13", "35|36", "18|14",
## "18|14", "20|11", "26|5", "19|12"), metaecosystem_type = structure(c(1L,
## 3L, 1L, 2L, 1L, 1L, 3L, 1L, 2L, 1L, 1L, 2L, 1L, 2L, 2L, 2L, 2L,
## 2L, 3L, 2L), levels = c("AD", "ED", "HD"), class = "factor"),
## metaeco_type_n_connection = c("AD unconnected", "HD unconnected",
## "AD unconnected", "ED unconnected", "AD unconnected", "AD unconnected",
## "HD connected", "AD unconnected", "ED unconnected", "AD unconnected",
## "AD unconnected", "ED unconnected", "AD unconnected", "ED unconnected",
## "ED connected", "ED unconnected", "ED unconnected", "ED unconnected",
## "HD unconnected", "ED unconnected"), connection = structure(c(1L,
## 1L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L,
## 1L, 1L, 1L, 1L), levels = c("unconnected", "connected"), class = "factor"),
## total_metaecosystem_bioarea_mm2 = c(553.795738377907, 185.286692943314,
## 122.615820680233, 155.706147889535, 459.185193353197, 343.596146454942,
## 237.570148046512, 358.734719393895, 483.636371494186, 352.433899281977,
## 122.615820680233, 176.534881587209, 122.615820680233, 155.706147889535,
## 307.962249239825, 169.025616824128, 194.155171848837, 267.402023267442,
## 188.796475098837, 157.851966806686)), row.names = c(NA, -20L
## ), class = "data.frame")